Repository: simple-icons/simple-icons
Pull request #7111 (2022-01-30 12:08:47)

Fix 3rd party extensions order, add test to avoid regression
Java 3rd party extension added in #7109 has not been added to the table in alphabetical order. This PR fixes that and adds a test to prevent this inconsistency in future PRs. Also, allows to reuse the function to get third party extensions from the README in [Webpack configuration of simple-icons-website](https://github.com/simple-icons/simple-icons-website/blob/2455e835b560859faffe5d06645eac11ae318a20/webpack.config.js#L21-L41), just the file `scripts/utils.js` needs to be downloaded as we do with SVGO configuration.

silentsoft: Oh, I didn't even notice that was in alphabetical order.. my bad :sob: sorry about that

Patch:
diff --git a/README.md b/README.md
index 4d1f7f18..06ded9d7 100644
--- a/README.md
+++ b/README.md
@@ -149,6 +149,7 @@ echo file_get_contents('path/to/package/icons/simpleicons.svg');
 | <img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/flutter.svg#gh-light-mode-only" alt="Flutter" align=left width=24 height=24><img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/assets/readme/flutter-white.svg#gh-dark-mode-only" alt="Flutter" align=left width=24 height=24> [Flutter package](https://pub.dev/packages/simple_icons) | [@jlnrrg](https://jlnrrg.github.io/) |
 | <img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/hexo.svg#gh-light-mode-only" alt="Hexo" align=left width=24 height=24><img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/assets/readme/hexo-white.svg#gh-dark-mode-only" alt="Hexo" align=left width=24 height=24> [Hexo plugin](https://github.com/nidbCN/hexo-simpleIcons) | [@nidbCN](https://github.com/nidbCN/) |
 | <img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/homeassistant.svg#gh-light-mode-only" alt="Home Assistant" align=left width=24 height=24><img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/assets/readme/homeassistant-white.svg#gh-dark-mode-only" alt="Home Assistant" align=left width=24 height=24> [Home Assistant plugin](https://github.com/vigonotion/hass-simpleicons) | [@vigonotion](https://github.com/vigonotion/) |
+| <img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/java.svg#gh-light-mode-only" alt="Java" align=left width=24 height=24><img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/assets/readme/java-white.svg#gh-dark-mode-only" alt="Java" align=left width=24 height=24> [Java library](https://github.com/silentsoft/simpleicons4j) | [@silentsoft](https://github.com/silentsoft) |
 | <img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/jetpackcompose.svg#gh-light-mode-only" alt="Jetpack Compose" align=left width=24 height=24><img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/assets/readme/jetpackcompose-white.svg#gh-dark-mode-only" alt="Jetpack Compose" align=left width=24 height=24> [Jetpack Compose library](https://github.com/DevSrSouza/compose-icons) | [@devsrsouza](https://github.com/devsrsouza/) |
 | <img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/kirby.svg#gh-light-mode-only" alt="Kirby" align=left width=24 height=24><img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/assets/readme/kirby-white.svg#gh-dark-mode-only" alt="Kirby" align=left width=24 height=24> [Kirby plugin](https://github.com/runxel/kirby3-simpleicons) | [@runxel](https://github.com/runxel) |
 | <img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/laravel.svg#gh-light-mode-only" alt="Laravel" align=left width=24 height=24><img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/assets/readme/laravel-white.svg#gh-dark-mode-only" alt="Laravel" align=left width=24 height=24> [Laravel Package](https://github.com/ublabs/blade-simple-icons) | [@adrian-ub](https://github.com/adrian-ub) |
@@ -157,7 +158,6 @@ echo file_get_contents('path/to/package/icons/simpleicons.svg');
 | <img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/svelte.svg#gh-light-mode-only" alt="Svelte" align=left width=24 height=24><img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/assets/readme/svelte-white.svg#gh-dark-mode-only" alt="Svelte" align=left width=24 height=24> [Svelte package](https://github.com/icons-pack/svelte-simple-icons) | [@wootsbot](https://github.com/wootsbot) |
 | <img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/vuedotjs.svg#gh-light-mode-only" alt="Vue" align=left width=24 height=24><img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/assets/readme/vuedotjs-white.svg#gh-dark-mode-only" alt="Vue" align=left width=24 height=24> [Vue package](https://github.com/mainvest/vue-simple-icons) | [@noahlitvin](https://github.com/noahlitvin) |
 | <img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/wordpress.svg#gh-light-mode-only" alt="Wordpress" align=left width=24 height=24><img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/assets/readme/wordpress-white.svg#gh-dark-mode-only" alt="Wordpress" align=left width=24 height=24> [WordPress plugin](https://wordpress.org/plugins/simple-icons/) | [@tjtaylo](https://github.com/tjtaylo) |
-| <img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/java.svg#gh-light-mode-only" alt="Java" align=left width=24 height=24><img src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/assets/readme/java-white.svg#gh-dark-mode-only" alt="Java" align=left width=24 height=24> [Java library](https://github.com/silentsoft/simpleicons4j) | [@silentsoft](https://github.com/silentsoft) |
 
 
 [slug]: ./slugs.md
diff --git a/scripts/utils.js b/scripts/utils.js
index f7256e6e..a38c863f 100644
--- a/scripts/utils.js
+++ b/scripts/utils.js
@@ -97,7 +97,7 @@ export const htmlFriendlyToTitle = (htmlFriendlyTitle) =>
  * Get contents of _data/simple-icons.json.
  */
 export const getIconsDataString = () => {
-  const __dirname = path.dirname(fileURLToPath(import.meta.url));
+  const __dirname = getDirnameFromImportMeta(import.meta.url);
   const rootDir = path.resolve(__dirname, '..');
   const iconDataPath = path.resolve(rootDir, '_data', 'simple-icons.json');
   return fs.readFile(iconDataPath, 'utf8');
@@ -117,3 +117,30 @@ export const getIconsData = async () => {
  */
 export const getDirnameFromImportMeta = (importMetaUrl) =>
   path.dirname(fileURLToPath(importMetaUrl));
+
+/**
+ * Get information about third party extensions.
+ */
+export const getThirdPartyExtensions = async () => {
+  const __dirname = getDirnameFromImportMeta(import.meta.url);
+  const readmePath = path.resolve(__dirname, '..', 'README.md');
+  const readmeContent = await fs.readFile(readmePath, 'utf8');
+  return readmeContent
+    .split('## Third-Party Extensions\n\n')[1]
+    .split('\n\n')[0]
+    .split('\n')
+    .slice(2)
+    .map((line) => {
+      const [module, author] = line.split(' | ');
+      return {
+        module: {
+          name: /\[(.+)\]/.exec(module)[1],
+          url: /\((.+)\)/.exec(module)[1],
+        },
+        author: {
+          name: /\[(.+)\]/.exec(author)[1],
+          url: /\((.+)\)/.exec(author)[1],
+        },
+      };
+    });
+};


Test patch:
diff --git a/tests/readme-icons.test.js b/tests/readme-icons.test.js
deleted file mode 100644
index 76e8d9ec..00000000
--- a/tests/readme-icons.test.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import fs from 'node:fs';
-import path from 'node:path';
-import { fileURLToPath } from 'node:url';
-import { test } from 'mocha';
-import { strict as assert } from 'node:assert';
-
-const __dirname = path.dirname(fileURLToPath(import.meta.url));
-const root = path.dirname(__dirname);
-const blackIconsPath = path.join(root, 'icons');
-const whiteIconsPath = path.join(root, 'assets', 'readme');
-const whiteIconsFileNames = fs.readdirSync(whiteIconsPath);
-
-for (let whiteIconFileName of whiteIconsFileNames) {
-  const whiteIconPath = path.join(whiteIconsPath, whiteIconFileName);
-  const blackIconPath = path.join(
-    blackIconsPath,
-    whiteIconFileName.replace(/-white\.svg$/, '.svg'),
-  );
-  const whiteIconRelPath = path.relative(root, whiteIconPath);
-  const blackIconRelPath = path.relative(root, blackIconPath);
-
-  test(`'${whiteIconRelPath}' content must be equivalent to '${blackIconRelPath}' content`, () => {
-    assert.ok(
-      whiteIconFileName.endsWith('-white.svg'),
-      `README icon assets file name '${whiteIconFileName}'` +
-        " must ends with '-white.svg'.",
-    );
-
-    assert.ok(
-      fs.existsSync(blackIconPath),
-      `Corresponding icon '${blackIconRelPath}' for README asset '${whiteIconRelPath}'` +
-        ` not found in '${path.dirname(blackIconRelPath)}' directory.`,
-    );
-
-    const whiteIconContent = fs.readFileSync(whiteIconPath, 'utf8');
-    const blackIconContent = fs.readFileSync(blackIconPath, 'utf8');
-    assert.equal(
-      whiteIconContent,
-      blackIconContent.replace('<svg', '<svg fill="white"'),
-    );
-  });
-}
diff --git a/tests/readme.test.js b/tests/readme.test.js
new file mode 100644
index 00000000..8ba82f55
--- /dev/null
+++ b/tests/readme.test.js
@@ -0,0 +1,64 @@
+import fs from 'node:fs';
+import path from 'node:path';
+import { describe, test } from 'mocha';
+import { strict as assert } from 'node:assert';
+import {
+  getThirdPartyExtensions,
+  getDirnameFromImportMeta,
+} from '../scripts/utils.js';
+
+const __dirname = getDirnameFromImportMeta(import.meta.url);
+const root = path.dirname(__dirname);
+
+describe('README icons assets must be consistent with Github themes', () => {
+  const blackIconsPath = path.join(root, 'icons');
+  const whiteIconsPath = path.join(root, 'assets', 'readme');
+  const whiteIconsFileNames = fs.readdirSync(whiteIconsPath);
+
+  for (let whiteIconFileName of whiteIconsFileNames) {
+    const whiteIconPath = path.join(whiteIconsPath, whiteIconFileName);
+    const blackIconPath = path.join(
+      blackIconsPath,
+      whiteIconFileName.replace(/-white\.svg$/, '.svg'),
+    );
+    const whiteIconRelPath = path.relative(root, whiteIconPath);
+    const blackIconRelPath = path.relative(root, blackIconPath);
+
+    test(`'${whiteIconRelPath}' content must be equivalent to '${blackIconRelPath}' content`, () => {
+      assert.ok(
+        whiteIconFileName.endsWith('-white.svg'),
+        `README icon assets file name '${whiteIconFileName}'` +
+          " must ends with '-white.svg'.",
+      );
+
+      assert.ok(
+        fs.existsSync(blackIconPath),
+        `Corresponding icon '${blackIconRelPath}' for README asset '${whiteIconRelPath}'` +
+          ` not found in '${path.dirname(blackIconRelPath)}' directory.`,
+      );
+
+      const whiteIconContent = fs.readFileSync(whiteIconPath, 'utf8');
+      const blackIconContent = fs.readFileSync(blackIconPath, 'utf8');
+      assert.equal(
+        whiteIconContent,
+        blackIconContent.replace('<svg', '<svg fill="white"'),
+      );
+    });
+  }
+});
+
+test('README third party extensions must be alphabetically sorted', async () => {
+  const thirdPartyExtensions = await getThirdPartyExtensions();
+  assert.ok(thirdPartyExtensions.length > 0);
+
+  const thirdPartyExtensionsNames = thirdPartyExtensions.map(
+    (ext) => ext.module.name,
+  );
+
+  const expectedOrder = thirdPartyExtensionsNames.slice().sort();
+  assert.deepEqual(
+    thirdPartyExtensionsNames,
+    expectedOrder,
+    'Wrong alphabetical order of third party extensions in README.',
+  );
+});