diff --git a/.jsonschema.json b/.jsonschema.json index e6134f20950f..58b00dc84806 100644 --- a/.jsonschema.json +++ b/.jsonschema.json @@ -231,8 +231,9 @@ }, "url": { "$id": "#url", + "description": "HTTPS-only URL for a source", "type": "string", - "pattern": "^https?://[^\\s]+$" + "pattern": "^https://[^\\s]+$" } }, "type": "object", diff --git a/.svglintrc.mjs b/.svglintrc.mjs index 85fbd6cc569e..4733e2a2c1a8 100644 --- a/.svglintrc.mjs +++ b/.svglintrc.mjs @@ -3,6 +3,7 @@ import path from 'node:path'; import { getDirnameFromImportMeta, htmlFriendlyToTitle, + collator, } from './scripts/utils.js'; import svgpath from 'svgpath'; import svgPathBbox from 'svg-path-bbox'; @@ -46,7 +47,7 @@ const sortObjectByKey = (obj) => { const sortObjectByValue = (obj) => { return Object.keys(obj) - .sort((a, b) => ('' + obj[a]).localeCompare(obj[b])) + .sort((a, b) => collator.compare(obj[a], obj[b])) .reduce((r, k) => Object.assign(r, { [k]: obj[k] }), {}); }; diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c89ec0c48cfc..e5b6682ae939 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -265,6 +265,8 @@ Here is the object of a fictional brand as an example: } ``` +You can use `npm run add-icon-data` to add metadata via a CLI prompt. + Make sure the icon is added in alphabetical order. If you're in doubt, you can always run `npm run our-lint` - this will tell you if any of the JSON data is in the wrong order. #### Optional Data @@ -291,6 +293,8 @@ Here is the object of the fictional brand from before, but with all optional val } ``` +> Non secured HTTP URLs are forbidden. If a brand's website only supports HTTP, you must still declare the URL using the `https://` protocol. + #### Source Guidelines We use the source URL as a reference for the current SVG in our repository and as a jumping-off point to find updates if the logo changes. If you used one of the sources listed below, make sure to follow these guidelines. If you're unsure about the source URL you can open a Pull Request and ask for help from others. diff --git a/LICENSE.md b/LICENSE.md index da5b887934e1..f0f4b0328708 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -27,4 +27,4 @@ For these and/or other purposes and motivations, and without any expectation of 3. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person’s Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. 4. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. -For more information, please see http://creativecommons.org/publicdomain/zero/1.0/. +For more information, please see https://creativecommons.org/publicdomain/zero/1.0/. diff --git a/_data/simple-icons.json b/_data/simple-icons.json index 304142bcdaa5..afb6b860c5ca 100644 --- a/_data/simple-icons.json +++ b/_data/simple-icons.json @@ -118,12 +118,12 @@ { "title": "ACM", "hex": "0085CA", - "source": "http://identitystandards.acm.org/" + "source": "https://identitystandards.acm.org/" }, { "title": "ActiGraph", "hex": "0B2C4A", - "source": "http://www.actigraphcorp.com/" + "source": "https://www.actigraphcorp.com/" }, { "title": "Activision", @@ -148,7 +148,7 @@ { "title": "AddThis", "hex": "FF6550", - "source": "http://www.addthis.com/" + "source": "https://www.addthis.com/" }, { "title": "AdGuard", @@ -160,6 +160,11 @@ "hex": "000000", "source": "https://www.adidas.com" }, + { + "title": "Adminer", + "hex": "34567C", + "source": "https://www.adminer.org/" + }, { "title": "Adobe", "hex": "FF0000", @@ -260,7 +265,7 @@ { "title": "Aerospike", "hex": "C41E25", - "source": "http://pages.aerospike.com/rs/aerospike/images/Acid_Whitepaper.pdf" + "source": "https://pages.aerospike.com/rs/aerospike/images/Acid_Whitepaper.pdf" }, { "title": "AEW", @@ -330,7 +335,7 @@ { "title": "Air China", "hex": "E30E17", - "source": "http://www.airchina.com.cn/en/investor_relations/" + "source": "https://www.airchina.com.cn/en/investor_relations/" }, { "title": "Air France", @@ -405,7 +410,7 @@ { "title": "Alfa Romeo", "hex": "981E32", - "source": "http://www.fcaci.com/x/Alfa" + "source": "https://www.fcaci.com/x/Alfa" }, { "title": "Alfred", @@ -460,7 +465,7 @@ { "title": "AlloCiné", "hex": "FECC00", - "source": "http://www.allocine.fr/" + "source": "https://www.allocine.fr/" }, { "title": "AllTrails", @@ -580,6 +585,11 @@ "hex": "FC4C02", "source": "https://www.amazon.com/gp/help/customer/display.html?nodeId=201348270" }, + { + "title": "Amazon Games", + "hex": "FF9900", + "source": "https://www.amazongames.com" + }, { "title": "Amazon Lumberyard", "hex": "66459B", @@ -786,7 +796,7 @@ { "title": "Apache CloudStack", "hex": "2AA5DC", - "source": "http://cloudstack.apache.org/trademark-guidelines.html" + "source": "https://cloudstack.apache.org/trademark-guidelines.html" }, { "title": "Apache Cordova", @@ -1259,7 +1269,7 @@ { "title": "Azure DevOps", "hex": "0078D7", - "source": "http://azure.com/devops" + "source": "https://azure.microsoft.com/products/devops/" }, { "title": "Azure Functions", @@ -1617,7 +1627,7 @@ { "title": "Bootstrap", "hex": "7952B3", - "source": "http://getbootstrap.com/about" + "source": "https://getbootstrap.com/about" }, { "title": "BorgBackup", @@ -1802,6 +1812,11 @@ "hex": "7ED321", "source": "https://cachethq.io/press" }, + { + "title": "CafePress", + "hex": "58A616", + "source": "https://en.wikipedia.org/wiki/CafePress#/media/File:CafePress_logo.svg" + }, { "title": "Caffeine", "hex": "0000FF", @@ -1875,7 +1890,7 @@ { "title": "Castro", "hex": "00B265", - "source": "http://supertop.co/castro/press/" + "source": "https://supertop.co/castro/press/" }, { "title": "Caterpillar", @@ -2177,7 +2192,7 @@ { "title": "Co-op", "hex": "00B1E7", - "source": "http://www.co-operative.coop/corporate/press/logos/" + "source": "https://www.co-operative.coop/media/assets" }, { "title": "Cockpit", @@ -2256,7 +2271,7 @@ { "title": "Codeforces", "hex": "1F8ACB", - "source": "http://codeforces.com/" + "source": "https://codeforces.com/" }, { "title": "CodeIgniter", @@ -2579,12 +2594,12 @@ { "title": "CSS Wizardry", "hex": "F43059", - "source": "http://csswizardry.com" + "source": "https://csswizardry.com" }, { "title": "CSS3", "hex": "1572B6", - "source": "http://www.w3.org/html/logo/" + "source": "https://www.w3.org/html/logo/" }, { "title": "Cucumber", @@ -2827,7 +2842,7 @@ "title": "del.icio.us", "slug": "delicious", "hex": "0000FF", - "source": "http://del.icio.us/", + "source": "https://del.icio.us/", "aliases": { "aka": [ "Delicious" @@ -2901,7 +2916,7 @@ { "title": "DeviantArt", "hex": "05CC47", - "source": "http://help.deviantart.com/21" + "source": "https://help.deviantart.com/21" }, { "title": "Devpost", @@ -3048,8 +3063,8 @@ }, { "title": "Douban", - "hex": "007722", - "source": "https://zh.wikipedia.org/wiki/Douban", + "hex": "2D963D", + "source": "https://www.douban.com/about", "license": { "type": "custom", "url": "https://www.douban.com/about/legal#info_data" @@ -3286,6 +3301,11 @@ "hex": "47848F", "source": "https://www.electronjs.org/" }, + { + "title": "Electron Fiddle", + "hex": "E79537", + "source": "https://github.com/electron/fiddle" + }, { "title": "electron-builder", "hex": "FFFFFF", @@ -3361,7 +3381,7 @@ { "title": "Empire Kred", "hex": "72BE50", - "source": "http://www.empire.kred" + "source": "https://www.empire.kred" }, { "title": "Enpass", @@ -3509,7 +3529,7 @@ { "title": "Expo", "hex": "000020", - "source": "http://expo.io/brand/" + "source": "https://expo.io/brand/" }, { "title": "Express", @@ -3592,6 +3612,16 @@ "hex": "FA005A", "source": "https://fandomdesignsystem.com/" }, + { + "title": "Fanfou", + "hex": "00CCFF", + "source": "https://fanfou.com" + }, + { + "title": "Fantom", + "hex": "0928FF", + "source": "https://fantom.foundation/" + }, { "title": "FARFETCH", "hex": "000000", @@ -3635,7 +3665,7 @@ { "title": "FeatHub", "hex": "9B9B9B", - "source": "http://feathub.com/" + "source": "https://feathub.com/" }, { "title": "FedEx", @@ -3676,7 +3706,7 @@ { "title": "Fiat", "hex": "941711", - "source": "http://www.fcaci.com/x/FIATv15" + "source": "https://www.fcaci.com/x/FIATv15" }, { "title": "Fido Alliance", @@ -3745,7 +3775,7 @@ { "title": "Fitbit", "hex": "00B0B9", - "source": "http://www.fitbit.com/uk/home" + "source": "https://www.fitbit.com/uk/home" }, { "title": "FITE", @@ -3850,7 +3880,7 @@ { "title": "Fnac", "hex": "E1A925", - "source": "http://www.fnac.com/" + "source": "https://www.fnac.com/" }, { "title": "Folium", @@ -3895,7 +3925,7 @@ { "title": "Fortinet", "hex": "EE3124", - "source": "http://www.fortinet.com/" + "source": "https://www.fortinet.com/" }, { "title": "Fortran", @@ -4042,6 +4072,16 @@ "hex": "000000", "source": "https://upload.wikimedia.org/wikipedia/commons/4/41/Game_and_watch_logo.svg" }, + { + "title": "Game Developer", + "hex": "E60012", + "source": "https://www.gamedeveloper.com/", + "aliases": { + "aka": [ + "Gamasutra" + ] + } + }, { "title": "Game Jolt", "hex": "CCFF00", @@ -4139,7 +4179,7 @@ { "title": "Git", "hex": "F05032", - "source": "http://git-scm.com/downloads/logos", + "source": "https://git-scm.com/downloads/logos", "license": { "type": "CC-BY-3.0" } @@ -4341,7 +4381,7 @@ { "title": "GoldenLine", "hex": "FFE005", - "source": "http://www.goldenline.pl" + "source": "https://www.goldenline.pl" }, { "title": "Goodreads", @@ -4535,7 +4575,7 @@ { "title": "Google Sheets", "hex": "34A853", - "source": "http://sheets.google.com/" + "source": "https://sheets.google.com/" }, { "title": "Google Street View", @@ -4602,7 +4642,7 @@ { "title": "Grav", "hex": "221E1F", - "source": "http://getgrav.org/media" + "source": "https://getgrav.org/media" }, { "title": "Gravatar", @@ -4804,7 +4844,7 @@ { "title": "Hatena Bookmark", "hex": "00A4DE", - "source": "http://hatenacorp.jp/press/resource" + "source": "https://hatenacorp.jp/press/resource" }, { "title": "haveibeenpwned", @@ -5009,7 +5049,7 @@ { "title": "HTML5", "hex": "E34F26", - "source": "http://www.w3.org/html/logo/" + "source": "https://www.w3.org/html/logo/" }, { "title": "HTTPie", @@ -5313,6 +5353,11 @@ "source": "https://www.jetbrains.com/idea/", "guidelines": "https://www.jetbrains.com/company/brand/" }, + { + "title": "Interaction Design Foundation", + "hex": "2B2B2B", + "source": "https://www.interaction-design.org/" + }, { "title": "InteractJS", "hex": "2599ED", @@ -5428,7 +5473,7 @@ "title": "Jabber", "hex": "CC0000", "source": "https://commons.wikimedia.org/wiki/File:Jabber-bulb.svg", - "guidelines": "http://www.jabber.org/faq.html#logo", + "guidelines": "https://www.jabber.org/faq.html#logo", "license": { "type": "CC-BY-2.5" } @@ -5480,8 +5525,8 @@ { "title": "Jeep", "hex": "000000", - "source": "http://www.fcaci.com/x/JEEPv15", - "guidelines": "http://www.fcaci.com/x/JEEPv15" + "source": "https://www.fcaci.com/x/JEEPv15", + "guidelines": "https://www.fcaci.com/x/JEEPv15" }, { "title": "Jekyll", @@ -5632,6 +5677,11 @@ "hex": "F7DF1E", "source": "https://cssinjs.org/" }, + { + "title": "JUKE", + "hex": "6CD74A", + "source": "https://juke.nl/" + }, { "title": "Julia", "hex": "9558B2", @@ -5939,8 +5989,8 @@ { "title": "Komoot", "hex": "6AA127", - "source": "http://newsroom.komoot.com/media_kits/219423/", - "guidelines": "http://newsroom.komoot.com/media_kits/219423/" + "source": "https://newsroom.komoot.com/media_kits/219423/", + "guidelines": "https://newsroom.komoot.com/media_kits/219423/" }, { "title": "Konami", @@ -6232,8 +6282,8 @@ { "title": "LINE", "hex": "00C300", - "source": "http://line.me/en/logo", - "guidelines": "http://line.me/en/logo" + "source": "https://line.me/en/logo", + "guidelines": "https://line.me/en/logo" }, { "title": "LineageOS", @@ -6329,7 +6379,7 @@ { "title": "LiveJournal", "hex": "00B0EA", - "source": "http://www.livejournal.com" + "source": "https://www.livejournal.com" }, { "title": "Livewire", @@ -6454,6 +6504,11 @@ "hex": "000000", "source": "https://commons.wikimedia.org/wiki/File:MacOS_wordmark_(2017).svg" }, + { + "title": "MacPaw", + "hex": "000000", + "source": "https://macpaw.com" + }, { "title": "Macy's", "hex": "E21A2C", @@ -6467,7 +6522,7 @@ { "title": "Magento", "hex": "EE672F", - "source": "http://magento.com" + "source": "https://magento.com" }, { "title": "Magisk", @@ -6482,8 +6537,8 @@ { "title": "MailChimp", "hex": "FFE01B", - "source": "http://mailchimp.com/about/brand-assets", - "guidelines": "http://mailchimp.com/about/brand-assets" + "source": "https://mailchimp.com/about/brand-assets", + "guidelines": "https://mailchimp.com/about/brand-assets" }, { "title": "Mailgun", @@ -6499,7 +6554,7 @@ { "title": "MakerBot", "hex": "FF1E0D", - "source": "http://www.makerbot.com/makerbot-press-assets" + "source": "https://www.makerbot.com/makerbot-press-assets" }, { "title": "MAMP", @@ -6620,7 +6675,7 @@ { "title": "Matternet", "hex": "261C29", - "source": "http://mttr.net" + "source": "https://mttr.net" }, { "title": "Max", @@ -6758,7 +6813,7 @@ { "title": "Meteor", "hex": "DE4F4F", - "source": "http://logo.meteorapp.com/" + "source": "https://logo.meteorapp.com/" }, { "title": "Metro", @@ -6798,7 +6853,7 @@ { "title": "Microgenetics", "hex": "FF0000", - "source": "http://microgenetics.co.uk/" + "source": "https://microgenetics.co.uk/" }, { "title": "MicroPython", @@ -7258,7 +7313,7 @@ { "title": "NetApp", "hex": "0067C5", - "source": "http://www.netapp.com/", + "source": "https://www.netapp.com/", "guidelines": "https://www.netapp.com/company/legal/trademark-guidelines/" }, { @@ -7588,7 +7643,7 @@ { "title": "OCaml", "hex": "EC6813", - "source": "http://ocaml.org/img/OCaml_Sticker.svg", + "source": "https://ocaml.org/img/OCaml_Sticker.svg", "guidelines": "https://ocaml.org/docs/logos.html", "license": { "type": "Unlicense" @@ -8044,7 +8099,7 @@ { "title": "Parity Substrate", "hex": "282828", - "source": "http://substrate.dev/" + "source": "https://substrate.dev/" }, { "title": "Parse.ly", @@ -8055,7 +8110,7 @@ { "title": "Passport", "hex": "34E27A", - "source": "http://www.passportjs.org/" + "source": "https://www.passportjs.org/" }, { "title": "Pastebin", @@ -8124,8 +8179,8 @@ { "title": "Pepsi", "hex": "2151A1", - "source": "http://gillettepepsicola.com/promotions-media/media-kit/", - "guidelines": "http://gillettepepsicola.com/promotions-media/media-kit/" + "source": "https://gillettepepsicola.com/promotions-media/media-kit/", + "guidelines": "https://gillettepepsicola.com/promotions-media/media-kit/" }, { "title": "Percy", @@ -8201,7 +8256,7 @@ { "title": "PHP", "hex": "777BB4", - "source": "http://php.net/download-logos.php", + "source": "https://php.net/download-logos.php", "license": { "type": "CC-BY-SA-4.0" } @@ -8397,7 +8452,7 @@ }, { "title": "Plex", - "hex": "E5A00D", + "hex": "EBAF00", "source": "https://brand.plex.tv/", "guidelines": "https://brand.plex.tv/" }, @@ -9089,8 +9144,8 @@ { "title": "Ram", "hex": "000000", - "source": "http://www.fcaci.com/x/RAMv15", - "guidelines": "http://www.fcaci.com/x/RAMv15" + "source": "https://www.fcaci.com/x/RAMv15", + "guidelines": "https://www.fcaci.com/x/RAMv15" }, { "title": "Rancher", @@ -9259,6 +9314,11 @@ "hex": "E41D1B", "source": "https://www.reebok.com/us" }, + { + "title": "Relay", + "hex": "F26B00", + "source": "https://relay.dev/" + }, { "title": "Reliance Industries Limited", "hex": "D1AB66", @@ -9325,6 +9385,12 @@ "hex": "00CCBB", "source": "https://c5.rgstatic.net/m/428059296771819/images/favicon/favicon.svg" }, + { + "title": "ReSharper", + "hex": "000000", + "source": "https://www.jetbrains.com/company/brand/logos/", + "guidelines": "https://www.jetbrains.com/company/brand/" + }, { "title": "Resurrection Remix OS", "hex": "000000", @@ -9573,7 +9639,7 @@ { "title": "Ruby on Rails", "hex": "CC0000", - "source": "http://rubyonrails.org/", + "source": "https://rubyonrails.org/", "guidelines": "https://rubyonrails.org/trademarks/" }, { @@ -9672,7 +9738,7 @@ { "title": "San Francisco Municipal Railway", "hex": "BA0C2F", - "source": "http://www.actransit.org/wp-content/uploads/HSP_CC-sched.pdf" + "source": "https://www.actransit.org/wp-content/uploads/HSP_CC-sched.pdf" }, { "title": "SanDisk", @@ -9692,8 +9758,8 @@ { "title": "Sass", "hex": "CC6699", - "source": "http://sass-lang.com/styleguide/brand", - "guidelines": "http://sass-lang.com/styleguide/brand", + "source": "https://sass-lang.com/styleguide/brand", + "guidelines": "https://sass-lang.com/styleguide/brand", "license": { "type": "CC-BY-NC-SA-3.0" } @@ -9861,8 +9927,8 @@ { "title": "Sencha", "hex": "86BC40", - "source": "http://design.sencha.com/", - "guidelines": "http://design.sencha.com/productlogo.html" + "source": "https://design.sencha.com/", + "guidelines": "https://design.sencha.com/productlogo.html" }, { "title": "Sennheiser", @@ -9893,7 +9959,7 @@ { "title": "Server Fault", "hex": "E7282D", - "source": "http://stackoverflow.com/company/logos", + "source": "https://stackoverflow.com/company/logos", "guidelines": "https://stackoverflow.com/legal/trademark-guidance" }, { @@ -9906,6 +9972,11 @@ "hex": "1AB394", "source": "https://sessionize.com/brand" }, + { + "title": "Setapp", + "hex": "E6C3A5", + "source": "https://setapp.com" + }, { "title": "SFML", "hex": "8CC445", @@ -9956,6 +10027,11 @@ "hex": "343434", "source": "https://shikimori.one" }, + { + "title": "Shopee", + "hex": "EE4D2D", + "source": "https://shopee.com" + }, { "title": "Shopify", "hex": "7AB55C", @@ -9998,6 +10074,11 @@ "hex": "3A76F0", "source": "https://github.com/signalapp/Signal-Desktop/blob/9db8765b6cf270195e45a7f251374d4e53d54c95/images/signal-logo.svg" }, + { + "title": "Similarweb", + "hex": "092540", + "source": "https://www.similarweb.com" + }, { "title": "Simkl", "hex": "000000", @@ -10035,7 +10116,7 @@ { "title": "SitePoint", "hex": "258AAF", - "source": "http://www.sitepoint.com" + "source": "https://www.sitepoint.com" }, { "title": "Sketch", @@ -10082,7 +10163,7 @@ { "title": "Skype", "hex": "00AFF0", - "source": "http://blogs.skype.com/?attachment_id=56273" + "source": "https://blogs.skype.com/?attachment_id=56273" }, { "title": "Skype for Business", @@ -10231,6 +10312,11 @@ "hex": "5294E2", "source": "https://getsol.us/branding/" }, + { + "title": "Sonar", + "hex": "FD3456", + "source": "https://www.sonarsource.com/" + }, { "title": "SonarCloud", "hex": "F3702A", @@ -10321,7 +10407,7 @@ { "title": "Spacemacs", "hex": "9266CC", - "source": "http://spacemacs.org/", + "source": "https://spacemacs.org/", "license": { "type": "CC-BY-SA-4.0" } @@ -10474,7 +10560,7 @@ "title": "Squarespace", "hex": "000000", "source": "https://www.squarespace.com/logo-guidelines", - "guidelines": "http://www.squarespace.com/brand-guidelines" + "guidelines": "https://www.squarespace.com/brand-guidelines" }, { "title": "SSRN", @@ -10484,7 +10570,7 @@ { "title": "Stack Exchange", "hex": "1E5397", - "source": "http://stackoverflow.com/company/logos", + "source": "https://stackoverflow.com/company/logos", "guidelines": "https://stackoverflow.com/legal/trademark-guidance" }, { @@ -10628,7 +10714,7 @@ { "title": "Stencyl", "hex": "8E1C04", - "source": "http://www.stencyl.com/about/press/" + "source": "https://www.stencyl.com/about/press/" }, { "title": "Stimulus", @@ -10696,7 +10782,7 @@ { "title": "StubHub", "hex": "003168", - "source": "http://www.stubhub.com" + "source": "https://www.stubhub.com" }, { "title": "styled-components", @@ -10736,7 +10822,7 @@ { "title": "Subversion", "hex": "809CC9", - "source": "http://subversion.apache.org/logo" + "source": "https://subversion.apache.org/logo" }, { "title": "suckless", @@ -10894,6 +10980,16 @@ "hex": "FFA900", "source": "https://www.tado.com/gb-en/press-assets" }, + { + "title": "Taichi Graphics", + "hex": "000000", + "source": "https://taichi.graphics" + }, + { + "title": "Taichi Lang", + "hex": "000000", + "source": "https://docs.taichi-lang.org/blog" + }, { "title": "Tails", "hex": "56347C", @@ -10915,6 +11011,11 @@ "hex": "FFFFFF", "source": "https://www.talenthouse.com/" }, + { + "title": "Tamiya", + "hex": "000000", + "source": "https://commons.wikimedia.org/wiki/File:TAMIYA_Logo.svg" + }, { "title": "Tampermonkey", "hex": "00485B", @@ -11199,6 +11300,11 @@ "hex": "4050FB", "source": "https://www.tide.co/newsroom/" }, + { + "title": "Tidyverse", + "hex": "1A162D", + "source": "https://github.com/rstudio/hex-stickers/blob/69528093ef59f541e5a4798dbcb00e60267e8870/SVG/tidyverse.svg" + }, { "title": "TietoEVRY", "hex": "063752", @@ -11222,7 +11328,7 @@ { "title": "Tinder", "hex": "FF6B6B", - "source": "http://www.gotinder.com/press" + "source": "https://www.gotinder.com/press" }, { "title": "TinyLetter", @@ -11495,7 +11601,7 @@ { "title": "Twoo", "hex": "FF7102", - "source": "http://www.twoo.com/about/press" + "source": "https://www.twoo.com/about/press" }, { "title": "Typeform", @@ -11894,6 +12000,11 @@ "hex": "F16728", "source": "https://cncf-branding.netlify.app/projects/vitess/" }, + { + "title": "Vitest", + "hex": "6E9F18", + "source": "https://vitest.dev/" + }, { "title": "Vivaldi", "hex": "EF3939", @@ -11913,7 +12024,7 @@ { "title": "VLC media player", "hex": "FF8800", - "source": "http://git.videolan.org/?p=vlc.git;a=tree;f=extras/package/macosx/asset_sources" + "source": "https://git.videolan.org/?p=vlc.git;a=tree;f=extras/package/macosx/asset_sources" }, { "title": "VMware", @@ -11955,6 +12066,11 @@ "hex": "000000", "source": "https://vscopress.co/media-kit" }, + { + "title": "VSCodium", + "hex": "2F80ED", + "source": "https://vscodium.com" + }, { "title": "VTEX", "hex": "ED125F", @@ -12036,6 +12152,11 @@ "hex": "004DB4", "source": "https://www.warnerbros.com/" }, + { + "title": "Warp", + "hex": "01A4FF", + "source": "https://warp.dev" + }, { "title": "wasmCloud", "hex": "00BC8E", @@ -12147,7 +12268,7 @@ { "title": "WEBTOON", "hex": "00D564", - "source": "http://webtoons.com/" + "source": "https://webtoons.com/" }, { "title": "WeChat", @@ -12300,7 +12421,7 @@ { "title": "Wire", "hex": "000000", - "source": "http://brand.wire.com", + "source": "https://brand.wire.com", "guidelines": "https://brand.wire.com/" }, { @@ -12333,7 +12454,7 @@ { "title": "Wix", "hex": "0C6EFC", - "source": "http://www.wix.com/about/design-assets" + "source": "https://www.wix.com/about/design-assets" }, { "title": "Wizz Air", @@ -12343,17 +12464,17 @@ { "title": "Wolfram", "hex": "DD1100", - "source": "http://company.wolfram.com/press-center/wolfram-corporate/" + "source": "https://company.wolfram.com/press-center/wolfram-corporate/" }, { "title": "Wolfram Language", "hex": "DD1100", - "source": "http://company.wolfram.com/press-center/language/" + "source": "https://company.wolfram.com/press-center/language/" }, { "title": "Wolfram Mathematica", "hex": "DD1100", - "source": "http://company.wolfram.com/press-center/mathematica/" + "source": "https://company.wolfram.com/press-center/mathematica/" }, { "title": "Woo", @@ -12713,6 +12834,11 @@ "hex": "006AFF", "source": "https://www.zillow.com/" }, + { + "title": "ZincSearch", + "hex": "5BA37F", + "source": "https://zincsearch.com/" + }, { "title": "Zingat", "hex": "009CFB", diff --git a/icons/adminer.svg b/icons/adminer.svg new file mode 100644 index 000000000000..915be0082876 --- /dev/null +++ b/icons/adminer.svg @@ -0,0 +1 @@ +Adminer \ No newline at end of file diff --git a/icons/amazongames.svg b/icons/amazongames.svg new file mode 100644 index 000000000000..950b408b05c2 --- /dev/null +++ b/icons/amazongames.svg @@ -0,0 +1 @@ +Amazon Games \ No newline at end of file diff --git a/icons/cafepress.svg b/icons/cafepress.svg new file mode 100644 index 000000000000..97f8ca573d6b --- /dev/null +++ b/icons/cafepress.svg @@ -0,0 +1 @@ +CafePress \ No newline at end of file diff --git a/icons/douban.svg b/icons/douban.svg index 0f5d0c0b2c98..cabc267da3e4 100644 --- a/icons/douban.svg +++ b/icons/douban.svg @@ -1 +1 @@ -Douban \ No newline at end of file +Douban \ No newline at end of file diff --git a/icons/electronfiddle.svg b/icons/electronfiddle.svg new file mode 100644 index 000000000000..85faa8a00e27 --- /dev/null +++ b/icons/electronfiddle.svg @@ -0,0 +1 @@ +Electron Fiddle \ No newline at end of file diff --git a/icons/fanfou.svg b/icons/fanfou.svg new file mode 100644 index 000000000000..32a0122e7168 --- /dev/null +++ b/icons/fanfou.svg @@ -0,0 +1 @@ +Fanfou \ No newline at end of file diff --git a/icons/fantom.svg b/icons/fantom.svg new file mode 100644 index 000000000000..e4b768670a37 --- /dev/null +++ b/icons/fantom.svg @@ -0,0 +1 @@ +Fantom \ No newline at end of file diff --git a/icons/gamedeveloper.svg b/icons/gamedeveloper.svg new file mode 100644 index 000000000000..26624680267c --- /dev/null +++ b/icons/gamedeveloper.svg @@ -0,0 +1 @@ +Game Developer \ No newline at end of file diff --git a/icons/interactiondesignfoundation.svg b/icons/interactiondesignfoundation.svg new file mode 100644 index 000000000000..c708c20ef4f2 --- /dev/null +++ b/icons/interactiondesignfoundation.svg @@ -0,0 +1 @@ +Interaction Design Foundation \ No newline at end of file diff --git a/icons/juke.svg b/icons/juke.svg new file mode 100644 index 000000000000..5de22de44238 --- /dev/null +++ b/icons/juke.svg @@ -0,0 +1 @@ +JUKE \ No newline at end of file diff --git a/icons/macpaw.svg b/icons/macpaw.svg new file mode 100644 index 000000000000..24ba8444691b --- /dev/null +++ b/icons/macpaw.svg @@ -0,0 +1 @@ +MacPaw \ No newline at end of file diff --git a/icons/plex.svg b/icons/plex.svg index 8e74c5e71dae..87379e14fd1a 100644 --- a/icons/plex.svg +++ b/icons/plex.svg @@ -1 +1 @@ -Plex \ No newline at end of file +Plex \ No newline at end of file diff --git a/icons/relay.svg b/icons/relay.svg new file mode 100644 index 000000000000..d188cff4512d --- /dev/null +++ b/icons/relay.svg @@ -0,0 +1 @@ +Relay \ No newline at end of file diff --git a/icons/resharper.svg b/icons/resharper.svg new file mode 100644 index 000000000000..d3ba5cfc3ae8 --- /dev/null +++ b/icons/resharper.svg @@ -0,0 +1 @@ +ReSharper \ No newline at end of file diff --git a/icons/setapp.svg b/icons/setapp.svg new file mode 100644 index 000000000000..598cbb8138be --- /dev/null +++ b/icons/setapp.svg @@ -0,0 +1 @@ +Setapp \ No newline at end of file diff --git a/icons/shopee.svg b/icons/shopee.svg new file mode 100644 index 000000000000..1e4393f527d7 --- /dev/null +++ b/icons/shopee.svg @@ -0,0 +1 @@ +Shopee \ No newline at end of file diff --git a/icons/similarweb.svg b/icons/similarweb.svg new file mode 100644 index 000000000000..87565e6bbac5 --- /dev/null +++ b/icons/similarweb.svg @@ -0,0 +1 @@ +Similarweb \ No newline at end of file diff --git a/icons/sonar.svg b/icons/sonar.svg new file mode 100644 index 000000000000..935cf4bab2ea --- /dev/null +++ b/icons/sonar.svg @@ -0,0 +1 @@ +Sonar \ No newline at end of file diff --git a/icons/taichigraphics.svg b/icons/taichigraphics.svg new file mode 100644 index 000000000000..2cd9224892b9 --- /dev/null +++ b/icons/taichigraphics.svg @@ -0,0 +1 @@ +Taichi Graphics \ No newline at end of file diff --git a/icons/taichilang.svg b/icons/taichilang.svg new file mode 100644 index 000000000000..da69a2bd4a9b --- /dev/null +++ b/icons/taichilang.svg @@ -0,0 +1 @@ +Taichi Lang \ No newline at end of file diff --git a/icons/tamiya.svg b/icons/tamiya.svg new file mode 100644 index 000000000000..d62ce95c51fc --- /dev/null +++ b/icons/tamiya.svg @@ -0,0 +1 @@ +Tamiya \ No newline at end of file diff --git a/icons/tidyverse.svg b/icons/tidyverse.svg new file mode 100644 index 000000000000..1c389d036042 --- /dev/null +++ b/icons/tidyverse.svg @@ -0,0 +1 @@ +Tidyverse \ No newline at end of file diff --git a/icons/vitest.svg b/icons/vitest.svg new file mode 100644 index 000000000000..6462d399df0d --- /dev/null +++ b/icons/vitest.svg @@ -0,0 +1 @@ +Vitest \ No newline at end of file diff --git a/icons/vscodium.svg b/icons/vscodium.svg new file mode 100644 index 000000000000..6649f32adea8 --- /dev/null +++ b/icons/vscodium.svg @@ -0,0 +1 @@ +VSCodium \ No newline at end of file diff --git a/icons/warp.svg b/icons/warp.svg new file mode 100644 index 000000000000..b825120839ff --- /dev/null +++ b/icons/warp.svg @@ -0,0 +1 @@ +Warp \ No newline at end of file diff --git a/icons/zincsearch.svg b/icons/zincsearch.svg new file mode 100644 index 000000000000..e85b5e227b70 --- /dev/null +++ b/icons/zincsearch.svg @@ -0,0 +1 @@ +ZincSearch \ No newline at end of file diff --git a/package.json b/package.json index 307217657fee..69b4d23f52c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "simple-icons", - "version": "7.12.0", + "version": "7.13.0", "description": "SVG icons for popular brands https://simpleicons.org", "homepage": "https://simpleicons.org", "keywords": [ @@ -37,10 +37,13 @@ "url": "https://opencollective.com/simple-icons" }, "devDependencies": { + "chalk": "^5.0.1", "editorconfig-checker": "4.0.2", "esbuild": "0.15.6", "fake-diff": "1.0.0", + "get-relative-luminance": "^1.0.0", "husky": "8.0.1", + "inquirer": "^9.1.2", "is-ci": "3.0.1", "jsonschema": "1.4.1", "mocha": "10.0.0", @@ -71,7 +74,8 @@ "pretest": "npm run prepublishOnly", "posttest": "npm run postpublish", "svgo": "svgo --config svgo.config.js", - "get-filename": "node scripts/get-filename.js" + "get-filename": "node scripts/get-filename.js", + "add-icon-data": "node scripts/add-icon-data.js" }, "engines": { "node": ">=0.12.18" diff --git a/scripts/add-icon-data.js b/scripts/add-icon-data.js new file mode 100644 index 000000000000..1f116b823dda --- /dev/null +++ b/scripts/add-icon-data.js @@ -0,0 +1,137 @@ +import fs from 'node:fs/promises'; +import inquirer from 'inquirer'; +import chalk from 'chalk'; +import getRelativeLuminance from 'get-relative-luminance'; +import { + URL_REGEX, + collator, + getIconsDataString, + getIconDataPath, + writeIconsData, + titleToSlug, + normalizeColor, +} from './utils.js'; + +const hexPattern = /^#?[a-f0-9]{3,8}$/i; + +const iconsData = JSON.parse(await getIconsDataString()); + +const titleValidator = (text) => { + if (!text) return 'This field is required'; + if ( + iconsData.icons.find( + (x) => x.title === text || titleToSlug(x.title) === titleToSlug(text), + ) + ) + return 'This icon title or slug already exist'; + return true; +}; + +const hexValidator = (text) => + hexPattern.test(text) ? true : 'This should be a valid hex code'; + +const sourceValidator = (text) => + URL_REGEX.test(text) ? true : 'This should be a secure URL'; + +const hexTransformer = (text) => { + const color = normalizeColor(text); + const luminance = hexPattern.test(text) + ? getRelativeLuminance.default(`#${color}`) + : -1; + if (luminance === -1) return text; + return chalk.bgHex(`#${color}`).hex(luminance < 0.4 ? '#fff' : '#000')(text); +}; + +const getIconDataFromAnswers = (answers) => ({ + title: answers.title, + hex: answers.hex, + source: answers.source, + ...(answers.hasGuidelines ? { guidelines: answers.guidelines } : {}), + ...(answers.hasLicense + ? { + license: { + type: answers.licenseType, + ...(answers.licenseUrl ? { url: answers.licenseUrl } : {}), + }, + } + : {}), +}); + +const dataPrompt = [ + { + type: 'input', + name: 'title', + message: 'Title', + validate: titleValidator, + }, + { + type: 'input', + name: 'hex', + message: 'Hex', + validate: hexValidator, + filter: (text) => normalizeColor(text), + transformer: hexTransformer, + }, + { + type: 'input', + name: 'source', + message: 'Source', + validate: sourceValidator, + }, + { + type: 'confirm', + name: 'hasGuidelines', + message: 'The icon has brand guidelines?', + }, + { + type: 'input', + name: 'guidelines', + message: 'Guidelines', + validate: sourceValidator, + when: ({ hasGuidelines }) => hasGuidelines, + }, + { + type: 'confirm', + name: 'hasLicense', + message: 'The icon has brand license?', + }, + { + type: 'input', + name: 'licenseType', + message: 'License type', + validate: (text) => Boolean(text), + when: ({ hasLicense }) => hasLicense, + }, + { + type: 'input', + name: 'licenseUrl', + message: 'License URL', + suffix: ' (optional)', + validate: (text) => !Boolean(text) || sourceValidator(text), + when: ({ hasLicense }) => hasLicense, + }, + { + type: 'confirm', + name: 'confirm', + message: (answers) => { + const icon = getIconDataFromAnswers(answers); + return [ + 'About to write to simple-icons.json', + chalk.reset(JSON.stringify(icon, null, 4)), + chalk.reset('Is this OK?'), + ].join('\n\n'); + }, + }, +]; + +const answers = await inquirer.prompt(dataPrompt); +const icon = getIconDataFromAnswers(answers); + +if (answers.confirm) { + iconsData.icons.push(icon); + iconsData.icons.sort((a, b) => collator.compare(a.title, b.title)); + await writeIconsData(iconsData); +} else { + console.log('Aborted.'); + process.exit(1); +} diff --git a/scripts/build/package.js b/scripts/build/package.js index 0088eac93427..9c781b4e5349 100644 --- a/scripts/build/package.js +++ b/scripts/build/package.js @@ -18,6 +18,7 @@ import { slugToVariableName, getIconsData, getDirnameFromImportMeta, + collator, } from '../utils.js'; const __dirname = getDirnameFromImportMeta(import.meta.url); @@ -81,31 +82,30 @@ const build = async () => { }; // 'main' - const iconsBarrelMjs = []; - const iconsBarrelJs = []; - const iconsBarrelDts = []; - const buildIcons = []; - - await Promise.all( + const buildIcons = await Promise.all( icons.map(async (icon) => { const filename = getIconSlug(icon); const svgFilepath = path.resolve(iconsDir, `${filename}.svg`); icon.svg = (await fs.readFile(svgFilepath, UTF8)).replace(/\r?\n/, ''); icon.path = svgToPath(icon.svg); icon.slug = filename; - buildIcons.push(icon); - const iconObject = iconToObject(icon); - const iconExportName = slugToVariableName(icon.slug); - - // add object to the barrel file - iconsBarrelJs.push(`${iconExportName}:${iconObject},`); - iconsBarrelMjs.push(`export const ${iconExportName}=${iconObject}`); - iconsBarrelDts.push(`export const ${iconExportName}:I;`); + return { icon, iconObject, iconExportName }; }), ); + const iconsBarrelDts = []; + const iconsBarrelJs = []; + const iconsBarrelMjs = []; + + buildIcons.sort((a, b) => collator.compare(a.icon.title, b.icon.title)); + buildIcons.forEach(({ iconObject, iconExportName }) => { + iconsBarrelDts.push(`export const ${iconExportName}:I;`); + iconsBarrelJs.push(`${iconExportName}:${iconObject},`); + iconsBarrelMjs.push(`export const ${iconExportName}=${iconObject}`); + }); + // constants used in templates to reduce package size const constantsString = `const a='',b='';`; @@ -113,7 +113,7 @@ const build = async () => { const rawIndexJs = util.format( indexTemplate, constantsString, - buildIcons.map(iconToKeyValue).join(','), + buildIcons.map(({ icon }) => iconToKeyValue(icon)).join(','), ); await writeJs(indexFile, rawIndexJs); diff --git a/scripts/lint/ourlint.js b/scripts/lint/ourlint.js index 677775a4a7c3..3512a55b92fa 100644 --- a/scripts/lint/ourlint.js +++ b/scripts/lint/ourlint.js @@ -6,7 +6,7 @@ */ import fakeDiff from 'fake-diff'; -import { getIconsDataString, normalizeNewlines } from '../utils.js'; +import { getIconsDataString, normalizeNewlines, collator } from '../utils.js'; /** * Contains our tests so they can be isolated from each other. @@ -18,12 +18,12 @@ const TESTS = { const collector = (invalidEntries, icon, index, array) => { if (index > 0) { const prev = array[index - 1]; - const compare = icon.title.localeCompare(prev.title); - if (compare < 0) { + const comparison = collator.compare(icon.title, prev.title); + if (comparison < 0) { invalidEntries.push(icon); - } else if (compare === 0) { + } else if (comparison === 0) { if (prev.slug) { - if (!icon.slug || icon.slug.localeCompare(prev.slug) < 0) { + if (!icon.slug || collator.compare(icon.slug, prev.slug) < 0) { invalidEntries.push(icon); } } @@ -48,7 +48,7 @@ const TESTS = { /* Check the formatting of the data file */ prettified: async (data, dataString) => { const normalizedDataString = normalizeNewlines(dataString); - const dataPretty = `${JSON.stringify(data, null, ' ')}\n`; + const dataPretty = `${JSON.stringify(data, null, 4)}\n`; if (normalizedDataString !== dataPretty) { const dataDiff = fakeDiff(normalizedDataString, dataPretty); diff --git a/scripts/utils.js b/scripts/utils.js index db0fed588c19..8cf6cee36653 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -4,7 +4,7 @@ */ import path from 'node:path'; -import { promises as fs } from 'node:fs'; +import fs from 'node:fs/promises'; import { fileURLToPath } from 'node:url'; const TITLE_TO_SLUG_REPLACEMENTS = { @@ -28,6 +28,8 @@ const TITLE_TO_SLUG_CHARS_REGEX = RegExp( const TITLE_TO_SLUG_RANGE_REGEX = /[^a-z0-9]/g; +export const URL_REGEX = /^https:\/\/[^\s]+$/; + /** * Get the slug/filename for an icon. * @param {Object} icon The icon data as it appears in _data/simple-icons.json @@ -94,15 +96,22 @@ export const htmlFriendlyToTitle = (htmlFriendlyTitle) => ); /** - * Get contents of _data/simple-icons.json. + * Get path of _data/simpe-icons.json. * @param {String|undefined} rootDir Path to the root directory of the project. */ -export const getIconsDataString = (rootDir) => { +export const getIconDataPath = (rootDir) => { if (rootDir === undefined) { rootDir = path.resolve(getDirnameFromImportMeta(import.meta.url), '..'); } - const iconDataPath = path.resolve(rootDir, '_data', 'simple-icons.json'); - return fs.readFile(iconDataPath, 'utf8'); + return path.resolve(rootDir, '_data', 'simple-icons.json'); +}; + +/** + * Get contents of _data/simple-icons.json. + * @param {String|undefined} rootDir Path to the root directory of the project. + */ +export const getIconsDataString = (rootDir) => { + return fs.readFile(getIconDataPath(rootDir), 'utf8'); }; /** @@ -114,6 +123,19 @@ export const getIconsData = async (rootDir) => { return JSON.parse(fileContents).icons; }; +/** + * Write icons data to _data/simple-icons.json. + * @param {Object} iconsData Icons data object. + * @param {String|undefined} rootDir Path to the root directory of the project. + */ +export const writeIconsData = async (iconsData, rootDir) => { + return fs.writeFile( + getIconDataPath(rootDir), + `${JSON.stringify(iconsData, null, 4)}\n`, + 'utf8', + ); +}; + /** * Get the directory name where this file is located from `import.meta.url`, * equivalent to the `__dirname` global variable in CommonJS. @@ -130,6 +152,20 @@ export const normalizeNewlines = (text) => { return text.replace(/\r\n/g, '\n'); }; +/** + * Convert non-6-digit hex color to 6-digit. + * @param {String} text The color text + */ +export const normalizeColor = (text) => { + let color = text.replace('#', '').toUpperCase(); + if (color.length < 6) { + color = [...color.slice(0, 3)].map((x) => x.repeat(2)).join(''); + } else if (color.length > 6) { + color = color.slice(0, 6); + } + return color; +}; + /** * Get information about third party extensions. * @param {String} readmePath Path to the README file @@ -153,3 +189,13 @@ export const getThirdPartyExtensions = async (readmePath) => }, }; }); + +/** + * `Intl.Collator` object ready to be used for icon titles sorting. + * @type {Intl.Collator} + * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator + **/ +export const collator = new Intl.Collator('en', { + usage: 'search', + caseFirst: 'upper', +}); diff --git a/slugs.md b/slugs.md index 8de7af19f245..3f0382603b96 100644 --- a/slugs.md +++ b/slugs.md @@ -38,6 +38,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `AddThis` | `addthis` | | `AdGuard` | `adguard` | | `Adidas` | `adidas` | +| `Adminer` | `adminer` | | `Adobe` | `adobe` | | `Adobe Acrobat Reader` | `adobeacrobatreader` | | `Adobe After Effects` | `adobeaftereffects` | @@ -110,6 +111,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Amazon ECS` | `amazonecs` | | `Amazon EKS` | `amazoneks` | | `Amazon Fire TV` | `amazonfiretv` | +| `Amazon Games` | `amazongames` | | `Amazon Lumberyard` | `amazonlumberyard` | | `Amazon Pay` | `amazonpay` | | `Amazon Prime` | `amazonprime` | @@ -344,6 +346,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `C Sharp` | `csharp` | | `C++` | `cplusplus` | | `Cachet` | `cachet` | +| `CafePress` | `cafepress` | | `Caffeine` | `caffeine` | | `Cairo Metro` | `cairometro` | | `CakePHP` | `cakephp` | @@ -624,6 +627,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Elastic Stack` | `elasticstack` | | `Elasticsearch` | `elasticsearch` | | `Electron` | `electron` | +| `Electron Fiddle` | `electronfiddle` | | `electron-builder` | `electronbuilder` | | `Element` | `element` | | `elementary` | `elementary` | @@ -683,6 +687,8 @@ update the script at 'scripts/release/update-slugs-table.js'. | `FamPay` | `fampay` | | `Fandango` | `fandango` | | `Fandom` | `fandom` | +| `Fanfou` | `fanfou` | +| `Fantom` | `fantom` | | `FARFETCH` | `farfetch` | | `FastAPI` | `fastapi` | | `Fastify` | `fastify` | @@ -767,6 +773,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `G2` | `g2` | | `G2A` | `g2a` | | `Game & Watch` | `gameandwatch` | +| `Game Developer` | `gamedeveloper` | | `Game Jolt` | `gamejolt` | | `Garmin` | `garmin` | | `Gatling` | `gatling` | @@ -999,6 +1006,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Integromat` | `integromat` | | `Intel` | `intel` | | `IntelliJ IDEA` | `intellijidea` | +| `Interaction Design Foundation` | `interactiondesignfoundation` | | `InteractJS` | `interactjs` | | `Intercom` | `intercom` | | `Intermarche` | `intermarche` | @@ -1055,6 +1063,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `JSON` | `json` | | `JSON Web Tokens` | `jsonwebtokens` | | `JSS` | `jss` | +| `JUKE` | `juke` | | `Julia` | `julia` | | `Juniper Networks` | `junipernetworks` | | `JUnit5` | `junit5` | @@ -1205,6 +1214,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Lyft` | `lyft` | | `MAAS` | `maas` | | `macOS` | `macos` | +| `MacPaw` | `macpaw` | | `Macy's` | `macys` | | `Magasins U` | `magasinsu` | | `Magento` | `magento` | @@ -1709,6 +1719,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Redux-Saga` | `reduxsaga` | | `RedwoodJS` | `redwoodjs` | | `Reebok` | `reebok` | +| `Relay` | `relay` | | `Reliance Industries Limited` | `relianceindustrieslimited` | | `Remix` | `remix` | | `Ren'Py` | `renpy` | @@ -1721,6 +1732,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `ReScript` | `rescript` | | `RescueTime` | `rescuetime` | | `ResearchGate` | `researchgate` | +| `ReSharper` | `resharper` | | `Resurrection Remix OS` | `resurrectionremixos` | | `RetroArch` | `retroarch` | | `RetroPie` | `retropie` | @@ -1825,6 +1837,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Server Fault` | `serverfault` | | `Serverless` | `serverless` | | `Sessionize` | `sessionize` | +| `Setapp` | `setapp` | | `SFML` | `sfml` | | `Shadow` | `shadow` | | `Shanghai Metro` | `shanghaimetro` | @@ -1835,6 +1848,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Shenzhen Metro` | `shenzhenmetro` | | `Shields.io` | `shieldsdotio` | | `Shikimori` | `shikimori` | +| `Shopee` | `shopee` | | `Shopify` | `shopify` | | `Shopware` | `shopware` | | `Shotcut` | `shotcut` | @@ -1843,6 +1857,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Shutterstock` | `shutterstock` | | `Siemens` | `siemens` | | `Signal` | `signal` | +| `Similarweb` | `similarweb` | | `Simkl` | `simkl` | | `Simple Analytics` | `simpleanalytics` | | `Simple Icons` | `simpleicons` | @@ -1885,6 +1900,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Solidity` | `solidity` | | `Sololearn` | `sololearn` | | `Solus` | `solus` | +| `Sonar` | `sonar` | | `SonarCloud` | `sonarcloud` | | `SonarLint` | `sonarlint` | | `SonarQube` | `sonarqube` | @@ -2005,10 +2021,13 @@ update the script at 'scripts/release/update-slugs-table.js'. | `TableCheck` | `tablecheck` | | `Taco Bell` | `tacobell` | | `tado°` | `tado` | +| `Taichi Graphics` | `taichigraphics` | +| `Taichi Lang` | `taichilang` | | `Tails` | `tails` | | `Tailwind CSS` | `tailwindcss` | | `Talend` | `talend` | | `Talenthouse` | `talenthouse` | +| `Tamiya` | `tamiya` | | `Tampermonkey` | `tampermonkey` | | `Taobao` | `taobao` | | `Tapas` | `tapas` | @@ -2062,6 +2081,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Ticketmaster` | `ticketmaster` | | `Tidal` | `tidal` | | `Tide` | `tide` | +| `Tidyverse` | `tidyverse` | | `TietoEVRY` | `tietoevry` | | `TikTok` | `tiktok` | | `Tile` | `tile` | @@ -2195,6 +2215,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Visual Studio Code` | `visualstudiocode` | | `Vite` | `vite` | | `Vitess` | `vitess` | +| `Vitest` | `vitest` | | `Vivaldi` | `vivaldi` | | `Vivino` | `vivino` | | `VK` | `vk` | @@ -2207,6 +2228,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Vowpal Wabbit` | `vowpalwabbit` | | `VOX` | `vox` | | `VSCO` | `vsco` | +| `VSCodium` | `vscodium` | | `VTEX` | `vtex` | | `Vue.js` | `vuedotjs` | | `Vuetify` | `vuetify` | @@ -2221,6 +2243,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Walmart` | `walmart` | | `Wappalyzer` | `wappalyzer` | | `Warner Bros.` | `warnerbros` | +| `Warp` | `warp` | | `wasmCloud` | `wasmcloud` | | `Wasmer` | `wasmer` | | `Wattpad` | `wattpad` | @@ -2348,6 +2371,7 @@ update the script at 'scripts/release/update-slugs-table.js'. | `Zig` | `zig` | | `Zigbee` | `zigbee` | | `Zillow` | `zillow` | +| `ZincSearch` | `zincsearch` | | `Zingat` | `zingat` | | `Zoho` | `zoho` | | `Zoiper` | `zoiper` | diff --git a/tests/readme.test.js b/tests/docs.test.js similarity index 74% rename from tests/readme.test.js rename to tests/docs.test.js index 0f95718bf171..b29eb009e21e 100644 --- a/tests/readme.test.js +++ b/tests/docs.test.js @@ -5,6 +5,7 @@ import { strict as assert } from 'node:assert'; import { getThirdPartyExtensions, getDirnameFromImportMeta, + URL_REGEX, } from '../scripts/utils.js'; const __dirname = getDirnameFromImportMeta(import.meta.url); @@ -63,3 +64,26 @@ test('README third party extensions must be alphabetically sorted', async () => 'Wrong alphabetical order of third party extensions in README.', ); }); + +test('Only allow HTTPS links in documentation pages', async () => { + const ignoreHttpLinks = ['http://www.w3.org/2000/svg']; + + const docsFiles = fs + .readdirSync(root) + .filter((fname) => fname.endsWith('.md')); + + const linksGetter = new RegExp('http://[^\\s"\']+', 'g'); + for (let docsFile of docsFiles) { + const docsFilePath = path.join(root, docsFile); + const docsFileContent = fs.readFileSync(docsFilePath, 'utf8'); + + Array.from(docsFileContent.matchAll(linksGetter)).forEach((match) => { + const link = match[0]; + assert.ok( + ignoreHttpLinks.includes(link) || link.startsWith('https://'), + `Link '${link}' in '${docsFile}' (at index ${match.index})` + + ` must use the HTTPS protocol.`, + ); + }); + } +}); diff --git a/tests/test-icon.js b/tests/test-icon.js index d52083a003b4..a17a3c5ab229 100644 --- a/tests/test-icon.js +++ b/tests/test-icon.js @@ -2,6 +2,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { strict as assert } from 'node:assert'; import { describe, it } from 'mocha'; +import { URL_REGEX } from '../scripts/utils.js'; const iconsDir = path.resolve(process.cwd(), 'icons'); @@ -29,6 +30,7 @@ export const testIcon = (icon, subject, slug) => { it('has the correct "source"', () => { assert.equal(subject.source, icon.source); + assert.match(subject.source, URL_REGEX); }); it('has an "svg" value', () => { @@ -53,7 +55,7 @@ export const testIcon = (icon, subject, slug) => { if (icon.license.type === 'custom') { assert.equal(subject.license.url, icon.license.url); } else { - assert.match(subject.license.url, /^https?:\/\/[^\s]+$/); + assert.match(subject.license.url, URL_REGEX); } } else { assert.equal(subject.license, undefined);