diff --git a/__tests__/catalog-validation.test.js b/__tests__/catalog-validation.test.js index c44f89b..2839f6b 100644 --- a/__tests__/catalog-validation.test.js +++ b/__tests__/catalog-validation.test.js @@ -1,8 +1,12 @@ -import { describe, test, expect } from '@jest/globals'; -import { softwareCatalog } from '../src/data/software-catalog.js'; -import { configurations } from '../src/data/configurations.js'; +import { describe, test, expect, beforeAll } from '@jest/globals'; +import { loadTestSoftwareCatalog } from './test-helpers/load-software-catalog.js'; +import { loadTestConfigurations } from './test-helpers/load-configurations.js'; import { categories, configCategories } from '../src/data/categories.js'; +// Catalogs loaded asynchronously before tests run +let softwareCatalog; +let configurations; + // Extract valid category IDs from categories.js const VALID_SOFTWARE_CATEGORIES = categories.map(cat => cat.id); const VALID_CONFIG_CATEGORIES = configCategories.map(cat => cat.id); @@ -13,6 +17,12 @@ const isKebabCase = (str) => /^[a-z0-9]+(-[a-z0-9]+)*$/.test(str); const isHexColor = (str) => /^#[0-9A-Fa-f]{6}$/.test(str); const hasWingetFormat = (str) => str && str.includes('.'); +// Load catalogs before all tests +beforeAll(async () => { + softwareCatalog = await loadTestSoftwareCatalog(); + configurations = await loadTestConfigurations(); +}); + describe('Software Catalog Validation', () => { test('should have software items', () => { expect(softwareCatalog).toBeDefined(); @@ -26,59 +36,71 @@ describe('Software Catalog Validation', () => { expect(ids.length).toBe(uniqueIds.size); }); - test.each(softwareCatalog)('software "$name" should have valid schema', (item) => { - // Required fields - expect(item.id).toBeDefined(); - expect(typeof item.id).toBe('string'); - expect(item.id.length).toBeGreaterThan(0); + test('all software should have valid schema', () => { + softwareCatalog.forEach((item) => { + // Required fields + expect(item.id).toBeDefined(); + expect(typeof item.id).toBe('string'); + expect(item.id.length).toBeGreaterThan(0); - expect(item.name).toBeDefined(); - expect(typeof item.name).toBe('string'); - expect(item.name.length).toBeGreaterThan(0); + expect(item.name).toBeDefined(); + expect(typeof item.name).toBe('string'); + expect(item.name.length).toBeGreaterThan(0); - expect(item.description).toBeDefined(); - expect(typeof item.description).toBe('string'); - expect(item.description.length).toBeGreaterThan(0); + expect(item.description).toBeDefined(); + expect(typeof item.description).toBe('string'); + expect(item.description.length).toBeGreaterThan(0); - expect(item.category).toBeDefined(); - expect(typeof item.category).toBe('string'); + expect(item.category).toBeDefined(); + expect(typeof item.category).toBe('string'); - expect(item.wingetId).toBeDefined(); - expect(typeof item.wingetId).toBe('string'); - expect(item.wingetId.length).toBeGreaterThan(0); + expect(item.wingetId).toBeDefined(); + expect(typeof item.wingetId).toBe('string'); + expect(item.wingetId.length).toBeGreaterThan(0); - expect(item.icon).toBeDefined(); - expect(typeof item.icon).toBe('string'); - expect(item.icon.length).toBeGreaterThan(0); + expect(item.icon).toBeDefined(); + expect(typeof item.icon).toBe('string'); + expect(item.icon.length).toBeGreaterThan(0); - expect(item.popular).toBeDefined(); - expect(typeof item.popular).toBe('boolean'); + expect(item.popular).toBeDefined(); + expect(typeof item.popular).toBe('boolean'); - expect(item.requiresAdmin).toBeDefined(); - expect(typeof item.requiresAdmin).toBe('boolean'); + expect(item.requiresAdmin).toBeDefined(); + expect(typeof item.requiresAdmin).toBe('boolean'); - expect(item.license).toBeDefined(); - expect(typeof item.license).toBe('string'); + expect(item.license).toBeDefined(); + expect(typeof item.license).toBe('string'); + }); }); - test.each(softwareCatalog)('software "$name" ID should be kebab-case', (item) => { - expect(isKebabCase(item.id)).toBe(true); + test('all software IDs should be kebab-case', () => { + softwareCatalog.forEach((item) => { + expect(isKebabCase(item.id)).toBe(true); + }); }); - test.each(softwareCatalog)('software "$name" should have valid category (ENUM)', (item) => { - expect(VALID_SOFTWARE_CATEGORIES).toContain(item.category); + test('all software should have valid category (ENUM)', () => { + softwareCatalog.forEach((item) => { + expect(VALID_SOFTWARE_CATEGORIES).toContain(item.category); + }); }); - test.each(softwareCatalog)('software "$name" should have valid license (ENUM)', (item) => { - expect(VALID_LICENSES).toContain(item.license); + test('all software should have valid license (ENUM)', () => { + softwareCatalog.forEach((item) => { + expect(VALID_LICENSES).toContain(item.license); + }); }); - test.each(softwareCatalog)('software "$name" wingetId should have valid format', (item) => { - expect(hasWingetFormat(item.wingetId)).toBe(true); + test('all software wingetId should have valid format', () => { + softwareCatalog.forEach((item) => { + expect(hasWingetFormat(item.wingetId)).toBe(true); + }); }); - test.each(softwareCatalog.filter(item => item.iconColor))('software "$name" iconColor should be valid hex', (item) => { - expect(isHexColor(item.iconColor)).toBe(true); + test('all software with iconColor should have valid hex', () => { + softwareCatalog.filter(item => item.iconColor).forEach((item) => { + expect(isHexColor(item.iconColor)).toBe(true); + }); }); }); @@ -95,63 +117,77 @@ describe('Configurations Validation', () => { expect(ids.length).toBe(uniqueIds.size); }); - test.each(configurations)('configuration "$name" should have valid schema', (item) => { - // Required fields - expect(item.id).toBeDefined(); - expect(typeof item.id).toBe('string'); - expect(item.id.length).toBeGreaterThan(0); + test('all configurations should have valid schema', () => { + configurations.forEach((item) => { + // Required fields + expect(item.id).toBeDefined(); + expect(typeof item.id).toBe('string'); + expect(item.id.length).toBeGreaterThan(0); - expect(item.name).toBeDefined(); - expect(typeof item.name).toBe('string'); - expect(item.name.length).toBeGreaterThan(0); + expect(item.name).toBeDefined(); + expect(typeof item.name).toBe('string'); + expect(item.name.length).toBeGreaterThan(0); - expect(item.description).toBeDefined(); - expect(typeof item.description).toBe('string'); - expect(item.description.length).toBeGreaterThan(0); + expect(item.description).toBeDefined(); + expect(typeof item.description).toBe('string'); + expect(item.description.length).toBeGreaterThan(0); - expect(item.category).toBeDefined(); - expect(typeof item.category).toBe('string'); + expect(item.category).toBeDefined(); + expect(typeof item.category).toBe('string'); - expect(item.recommended).toBeDefined(); - expect(typeof item.recommended).toBe('boolean'); + expect(item.recommended).toBeDefined(); + expect(typeof item.recommended).toBe('boolean'); - expect(item.requiresRestart).toBeDefined(); - expect(typeof item.requiresRestart).toBe('boolean'); + expect(item.requiresRestart).toBeDefined(); + expect(typeof item.requiresRestart).toBe('boolean'); - expect(item.requiresAdmin).toBeDefined(); - expect(typeof item.requiresAdmin).toBe('boolean'); + expect(item.requiresAdmin).toBeDefined(); + expect(typeof item.requiresAdmin).toBe('boolean'); + }); }); - test.each(configurations)('configuration "$name" ID should be kebab-case', (item) => { - expect(isKebabCase(item.id)).toBe(true); + test('all configuration IDs should be kebab-case', () => { + configurations.forEach((item) => { + expect(isKebabCase(item.id)).toBe(true); + }); }); - test.each(configurations)('configuration "$name" should have valid category (ENUM)', (item) => { - expect(VALID_CONFIG_CATEGORIES).toContain(item.category); + test('all configurations should have valid category (ENUM)', () => { + configurations.forEach((item) => { + expect(VALID_CONFIG_CATEGORIES).toContain(item.category); + }); }); - test.each(configurations)('configuration "$name" should have at least one bat array', (item) => { - const hasRegistryBat = Array.isArray(item.registryBat) && item.registryBat.length > 0; - const hasCommandBat = Array.isArray(item.commandBat) && item.commandBat.length > 0; - expect(hasRegistryBat || hasCommandBat).toBe(true); + test('all configurations should have at least one bat array', () => { + configurations.forEach((item) => { + const hasRegistryBat = Array.isArray(item.registryBat) && item.registryBat.length > 0; + const hasCommandBat = Array.isArray(item.commandBat) && item.commandBat.length > 0; + expect(hasRegistryBat || hasCommandBat).toBe(true); + }); }); - test.each(configurations.filter(item => item.registryBat))('configuration "$name" registryBat should be array of strings', (item) => { - expect(Array.isArray(item.registryBat)).toBe(true); - item.registryBat.forEach(cmd => { - expect(typeof cmd).toBe('string'); + test('all configurations with registryBat should have array of strings', () => { + configurations.filter(item => item.registryBat).forEach((item) => { + expect(Array.isArray(item.registryBat)).toBe(true); + item.registryBat.forEach(cmd => { + expect(typeof cmd).toBe('string'); + }); }); }); - test.each(configurations.filter(item => item.commandBat))('configuration "$name" commandBat should be array of strings', (item) => { - expect(Array.isArray(item.commandBat)).toBe(true); - item.commandBat.forEach(cmd => { - expect(typeof cmd).toBe('string'); + test('all configurations with commandBat should have array of strings', () => { + configurations.filter(item => item.commandBat).forEach((item) => { + expect(Array.isArray(item.commandBat)).toBe(true); + item.commandBat.forEach(cmd => { + expect(typeof cmd).toBe('string'); + }); }); }); - test.each(configurations.filter(item => item.warning))('configuration "$name" warning should be a string', (item) => { - expect(typeof item.warning).toBe('string'); - expect(item.warning.length).toBeGreaterThan(0); + test('all configurations with warning should have string warning', () => { + configurations.filter(item => item.warning).forEach((item) => { + expect(typeof item.warning).toBe('string'); + expect(item.warning.length).toBeGreaterThan(0); + }); }); }); diff --git a/__tests__/test-helpers/load-configurations.js b/__tests__/test-helpers/load-configurations.js new file mode 100644 index 0000000..b60675d --- /dev/null +++ b/__tests__/test-helpers/load-configurations.js @@ -0,0 +1,30 @@ +/** + * Test helper for loading configurations in Jest environment + * Uses Node.js glob instead of Vite's import.meta.glob + */ + +import { glob } from 'glob'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const configurationsPath = path.join(__dirname, '../../src/data/configurations'); + +/** + * Load all configuration entries from the configurations directory + * @returns {Promise} Array of all configuration objects + */ +export const loadTestConfigurations = async () => { + const files = await glob('**/*.js', { cwd: configurationsPath }); + const items = []; + + for (const file of files) { + const fullPath = path.join(configurationsPath, file); + const module = await import(fullPath); + if (module.default) { + items.push(module.default); + } + } + + return items.sort((a, b) => a.name.localeCompare(b.name)); +}; diff --git a/__tests__/test-helpers/load-software-catalog.js b/__tests__/test-helpers/load-software-catalog.js new file mode 100644 index 0000000..c3a120e --- /dev/null +++ b/__tests__/test-helpers/load-software-catalog.js @@ -0,0 +1,30 @@ +/** + * Test helper for loading software catalog in Jest environment + * Uses Node.js glob instead of Vite's import.meta.glob + */ + +import { glob } from 'glob'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const softwarePath = path.join(__dirname, '../../src/data/software'); + +/** + * Load all software entries from the software directory + * @returns {Promise} Array of all software objects + */ +export const loadTestSoftwareCatalog = async () => { + const files = await glob('**/*.js', { cwd: softwarePath }); + const items = []; + + for (const file of files) { + const fullPath = path.join(softwarePath, file); + const module = await import(fullPath); + if (module.default) { + items.push(module.default); + } + } + + return items.sort((a, b) => a.name.localeCompare(b.name)); +}; diff --git a/package-lock.json b/package-lock.json index 3e31415..ee174fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "eslint": "^9.39.1", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.24", + "glob": "^13.0.0", "globals": "^16.5.0", "jest": "^30.2.0", "postcss": "^8.5.6", @@ -1258,6 +1259,29 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1613,6 +1637,77 @@ } } }, + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@jest/schemas": { "version": "30.0.5", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", @@ -2538,7 +2633,6 @@ "integrity": "sha512-rl78HwuZlaDIUSeUKkmogkhebA+8K1Hy7tddZuJ3D0xV8pZSfsYGTsliGUol1JPzu9EKnTxPC4L1fiWouStRew==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -4148,21 +4242,18 @@ } }, "node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", + "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", + "minimatch": "^10.1.1", "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "path-scurry": "^2.0.0" }, - "bin": { - "glob": "dist/esm/bin.mjs" + "engines": { + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4181,27 +4272,17 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "@isaacs/brace-expansion": "^5.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4686,6 +4767,77 @@ } } }, + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/jest-config/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/jest-config/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/jest-diff": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", @@ -4972,6 +5124,77 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/jest-snapshot": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", @@ -5907,28 +6130,31 @@ } }, "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", "dev": true, - "license": "ISC" + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } }, "node_modules/picocolors": { "version": "1.1.1", @@ -5943,7 +6169,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, diff --git a/package.json b/package.json index d9f6512..4bc34d7 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "eslint": "^9.39.1", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.24", + "glob": "^13.0.0", "globals": "^16.5.0", "jest": "^30.2.0", "postcss": "^8.5.6", diff --git a/src/data/configurations.js b/src/data/configurations.js index ed6e8e4..aecca46 100644 --- a/src/data/configurations.js +++ b/src/data/configurations.js @@ -1,259 +1,53 @@ /** * Configurations Aggregator - * Imports all configurations from individual files + * Auto-discovers all configurations from individual files using Vite's import.meta.glob */ -// ======================================== -// CLEANUP -// ======================================== -import disableFaxService from './configurations/cleanup/disable-fax-service.js'; -import disableMobileHotspot from './configurations/cleanup/disable-mobile-hotspot.js'; -import disableXboxLiveServices from './configurations/cleanup/disable-xbox-live-services.js'; -import remove3dViewer from './configurations/cleanup/remove-3d-viewer.js'; -import removeAlarmsClock from './configurations/cleanup/remove-alarms-clock.js'; -import removeBingNews from './configurations/cleanup/remove-bing-news.js'; -import removeBingWeather from './configurations/cleanup/remove-bing-weather.js'; -import removeCamera from './configurations/cleanup/remove-camera.js'; -import removeCasualGames from './configurations/cleanup/remove-casual-games.js'; -import removeClipchamp from './configurations/cleanup/remove-clipchamp.js'; -import removeGetHelp from './configurations/cleanup/remove-get-help.js'; -import removeMailCalendar from './configurations/cleanup/remove-mail-calendar.js'; -import removeMaps from './configurations/cleanup/remove-maps.js'; -import removeMicrosoftTips from './configurations/cleanup/remove-microsoft-tips.js'; -import removeMixedReality from './configurations/cleanup/remove-mixed-reality.js'; -import removeOfficeHub from './configurations/cleanup/remove-office-hub.js'; -import removeOnenoteUwp from './configurations/cleanup/remove-onenote-uwp.js'; -import removePaint3d from './configurations/cleanup/remove-paint-3d.js'; -import removeSkypePreinstalled from './configurations/cleanup/remove-skype-preinstalled.js'; -import removeSolitaire from './configurations/cleanup/remove-solitaire.js'; -import removeTeamsChat from './configurations/cleanup/remove-teams-chat.js'; -import removeVoiceRecorder from './configurations/cleanup/remove-voice-recorder.js'; -import removeWidgets from './configurations/cleanup/remove-widgets.js'; -import removeXboxAppsComplete from './configurations/cleanup/remove-xbox-apps-complete.js'; -import removeXboxGamebar from './configurations/cleanup/remove-xbox-gamebar.js'; -import removeYourPhone from './configurations/cleanup/remove-your-phone.js'; +// Eagerly import all configuration files at build time +const configModules = import.meta.glob('./configurations/**/*.js', { eager: true }); -// ======================================== -// FILE EXPLORER -// ======================================== -import disableFolderGrouping from './configurations/file-explorer/disable-folder-grouping.js'; -import disableQuickAccess from './configurations/file-explorer/disable-quick-access.js'; -import disableThumbnailCache from './configurations/file-explorer/disable-thumbnail-cache.js'; -import launchFolderWindows from './configurations/file-explorer/launch-folder-windows.js'; -import showDrivesNoMedia from './configurations/file-explorer/show-drives-no-media.js'; -import showFileExtensions from './configurations/file-explorer/show-file-extensions.js'; -import showFullPathTitle from './configurations/file-explorer/show-full-path-title.js'; -import showHiddenFiles from './configurations/file-explorer/show-hidden-files.js'; -import showStatusBar from './configurations/file-explorer/show-status-bar.js'; - -// ======================================== -// GAMING -// ======================================== -import competitiveGamingOptimizations from './configurations/gaming/competitive-gaming-optimizations.js'; -import disableGameDvr from './configurations/gaming/disable-game-dvr.js'; -import disableGameMode from './configurations/gaming/disable-game-mode.js'; -import disableNvidiaTelemetry from './configurations/gaming/disable-nvidia-telemetry.js'; -import enableHardwareGpuScheduling from './configurations/gaming/enable-hardware-gpu-scheduling.js'; - -// ======================================== -// NETWORK -// ======================================== -import disableWifiSense from './configurations/network/disable-wifi-sense.js'; -import setDnsCloudflare from './configurations/network/set-dns-cloudflare.js'; - -// ======================================== -// PERFORMANCE -// ======================================== -import cpuMaxPerformance from './configurations/performance/cpu-max-performance.js'; -import disableBackgroundApps from './configurations/performance/disable-background-apps.js'; -import disableHibernation from './configurations/performance/disable-hibernation.js'; -import disableStartupDelay from './configurations/performance/disable-startup-delay.js'; -import disableSysmain from './configurations/performance/disable-sysmain.js'; -import disableTransparency from './configurations/performance/disable-transparency.js'; -import disableVisualEffects from './configurations/performance/disable-visual-effects.js'; -import disableWindowsDefender from './configurations/performance/disable-windows-defender.js'; -import disableWindowsTips from './configurations/performance/disable-windows-tips.js'; -import highPerformancePower from './configurations/performance/high-performance-power.js'; -import ultimatePerformancePower from './configurations/performance/ultimate-performance-power.js'; - -// ======================================== -// PRIVACY -// ======================================== -import disableActivityHistory from './configurations/privacy/disable-activity-history.js'; -import disableAdvertisingId from './configurations/privacy/disable-advertising-id.js'; -import disableAppSuggestions from './configurations/privacy/disable-app-suggestions.js'; -import disableCeip from './configurations/privacy/disable-ceip.js'; -import disableCortana from './configurations/privacy/disable-cortana.js'; -import disableDiagnosticData from './configurations/privacy/disable-diagnostic-data.js'; -import disableErrorReporting from './configurations/privacy/disable-error-reporting.js'; -import disableFeedbackRequests from './configurations/privacy/disable-feedback-requests.js'; -import disableLocationTracking from './configurations/privacy/disable-location-tracking.js'; -import disableTailoredExperiences from './configurations/privacy/disable-tailored-experiences.js'; -import disableTelemetry from './configurations/privacy/disable-telemetry.js'; -import disableTimeline from './configurations/privacy/disable-timeline.js'; - -// ======================================== -// START MENU -// ======================================== -import disableBingSearch from './configurations/start-menu/disable-bing-search.js'; -import leftAlignTaskbarWin11 from './configurations/start-menu/left-align-taskbar-win11.js'; -import removeRecentItemsStart from './configurations/start-menu/remove-recent-items-start.js'; -import showAllTrayIcons from './configurations/start-menu/show-all-tray-icons.js'; - -// ======================================== -// UPDATES -// ======================================== -import disableAutoRestartUpdates from './configurations/updates/disable-auto-restart-updates.js'; -import disableWindowsUpdate from './configurations/updates/disable-windows-update.js'; - -// ======================================== -// VISUAL -// ======================================== -import classicContextMenuWin11 from './configurations/visual/classic-context-menu-win11.js'; -import darkMode from './configurations/visual/dark-mode.js'; -import disableTaskbarThumbnails from './configurations/visual/disable-taskbar-thumbnails.js'; -import hideSearchBox from './configurations/visual/hide-search-box.js'; -import hideTaskviewButton from './configurations/visual/hide-taskview-button.js'; -import removeOnedrive from './configurations/visual/remove-onedrive.js'; -import showFileCheckboxes from './configurations/visual/show-file-checkboxes.js'; -import showSecondsClock from './configurations/visual/show-seconds-clock.js'; -import smallTaskbarIcons from './configurations/visual/small-taskbar-icons.js'; - -export const configurations = [ - // ======================================== - // CLEANUP - // ======================================== - disableFaxService, - disableMobileHotspot, - disableXboxLiveServices, - remove3dViewer, - removeAlarmsClock, - removeBingNews, - removeBingWeather, - removeCamera, - removeCasualGames, - removeClipchamp, - removeGetHelp, - removeMailCalendar, - removeMaps, - removeMicrosoftTips, - removeMixedReality, - removeOfficeHub, - removeOnenoteUwp, - removePaint3d, - removeSkypePreinstalled, - removeSolitaire, - removeTeamsChat, - removeVoiceRecorder, - removeWidgets, - removeXboxAppsComplete, - removeXboxGamebar, - removeYourPhone, - - // ======================================== - // FILE EXPLORER - // ======================================== - disableFolderGrouping, - disableQuickAccess, - disableThumbnailCache, - launchFolderWindows, - showDrivesNoMedia, - showFileExtensions, - showFullPathTitle, - showHiddenFiles, - showStatusBar, - - // ======================================== - // GAMING - // ======================================== - competitiveGamingOptimizations, - disableGameDvr, - disableGameMode, - disableNvidiaTelemetry, - enableHardwareGpuScheduling, - - // ======================================== - // NETWORK - // ======================================== - disableWifiSense, - setDnsCloudflare, - - // ======================================== - // PERFORMANCE - // ======================================== - cpuMaxPerformance, - disableBackgroundApps, - disableHibernation, - disableStartupDelay, - disableSysmain, - disableTransparency, - disableVisualEffects, - disableWindowsDefender, - disableWindowsTips, - highPerformancePower, - ultimatePerformancePower, - - // ======================================== - // PRIVACY - // ======================================== - disableActivityHistory, - disableAdvertisingId, - disableAppSuggestions, - disableCeip, - disableCortana, - disableDiagnosticData, - disableErrorReporting, - disableFeedbackRequests, - disableLocationTracking, - disableTailoredExperiences, - disableTelemetry, - disableTimeline, - - // ======================================== - // START MENU - // ======================================== - disableBingSearch, - leftAlignTaskbarWin11, - removeRecentItemsStart, - showAllTrayIcons, - - // ======================================== - // UPDATES - // ======================================== - disableAutoRestartUpdates, - disableWindowsUpdate, +/** + * Process glob results into a flat array of configuration objects + * @returns {Array} Array of all configuration objects + */ +const loadConfigurations = () => { + const items = []; + + for (const path in configModules) { + const module = configModules[path]; + if (module.default) { + items.push(module.default); + } + } + + // Sort by name for consistent ordering + return items.sort((a, b) => a.name.localeCompare(b.name)); +}; - // ======================================== - // VISUAL - // ======================================== - classicContextMenuWin11, - darkMode, - disableTaskbarThumbnails, - hideSearchBox, - hideTaskviewButton, - removeOnedrive, - showFileCheckboxes, - showSecondsClock, - smallTaskbarIcons, -]; +export const configurations = loadConfigurations(); /** * Get configurations by category + * @param {string} categoryId - The category ID to filter by + * @returns {Array} Array of configurations in the specified category */ export const getConfigsByCategory = (categoryId) => { - return configurations.filter(config => config.category === categoryId); + return configurations.filter((config) => config.category === categoryId); }; /** * Get recommended configurations + * @returns {Array} Array of configurations marked as recommended */ export const getRecommendedConfigs = () => { - return configurations.filter(config => config.recommended); + return configurations.filter((config) => config.recommended); }; /** * Get configuration by ID + * @param {string} id - The configuration ID to find + * @returns {Object|undefined} The configuration object or undefined */ export const getConfigById = (id) => { - return configurations.find(config => config.id === id); + return configurations.find((config) => config.id === id); }; diff --git a/src/data/software-catalog.js b/src/data/software-catalog.js index 006c06e..a4649b6 100644 --- a/src/data/software-catalog.js +++ b/src/data/software-catalog.js @@ -1,323 +1,53 @@ /** * Software Catalog Aggregator - * Imports all software from individual files + * Auto-discovers all software from individual files using Vite's import.meta.glob */ -// Antivirus -import avast from './software/antivirus/avast.js'; -import avg from './software/antivirus/avg.js'; -import bitdefender from './software/antivirus/bitdefender.js'; -import clamwin from './software/antivirus/clamwin.js'; -import kaspersky from './software/antivirus/kaspersky.js'; +// Eagerly import all software files at build time +const softwareModules = import.meta.glob('./software/**/*.js', { eager: true }); -// Browsers -import brave from './software/browsers/brave.js'; -import chrome from './software/browsers/chrome.js'; -import chromium from './software/browsers/chromium.js'; -import firefox from './software/browsers/firefox.js'; -import opera from './software/browsers/opera.js'; -import vivaldi from './software/browsers/vivaldi.js'; - -// Cloud Storage -import box from './software/cloud-storage/box.js'; -import dropbox from './software/cloud-storage/dropbox.js'; -import googleDrive from './software/cloud-storage/google-drive.js'; -import icloud from './software/cloud-storage/icloud.js'; -import mega from './software/cloud-storage/mega.js'; -import protonDrive from './software/cloud-storage/proton-drive.js'; - -// Communication -import discord from './software/communication/discord.js'; -import mailbird from './software/communication/mailbird.js'; -import protonMailBridge from './software/communication/proton-mail-bridge.js'; -import signal from './software/communication/signal.js'; -import slack from './software/communication/slack.js'; -import teams from './software/communication/teams.js'; -import telegram from './software/communication/telegram.js'; -import thunderbird from './software/communication/thunderbird.js'; -import whatsapp from './software/communication/whatsapp.js'; -import zoom from './software/communication/zoom.js'; - -// Development -import androidStudio from './software/development/android-studio.js'; -import cmder from './software/development/cmder.js'; -import dbeaver from './software/development/dbeaver.js'; -import dockerDesktop from './software/development/docker-desktop.js'; -import git from './software/development/git.js'; -import githubDesktop from './software/development/github-desktop.js'; -import insomnia from './software/development/insomnia.js'; -import intellijCommunity from './software/development/intellij-community.js'; -import jetbrainsToolbox from './software/development/jetbrains-toolbox.js'; -import neovim from './software/development/neovim.js'; -import nodejs from './software/development/nodejs.js'; -import notepadPlusplus from './software/development/notepad-plusplus.js'; -import postman from './software/development/postman.js'; -import putty from './software/development/putty.js'; -import pycharmCommunity from './software/development/pycharm-community.js'; -import python from './software/development/python.js'; -import sublimeText from './software/development/sublime-text.js'; -import terminus from './software/development/terminus.js'; -import vscode from './software/development/vscode.js'; -import webstorm from './software/development/webstorm.js'; - -// Drivers -import amdAdrenalin from './software/drivers/amd-adrenalin.js'; -import driverBooster from './software/drivers/driver-booster.js'; -import driverEasy from './software/drivers/driver-easy.js'; -import nvidiaGeforceExperience from './software/drivers/nvidia-geforce-experience.js'; -import snappyDriver from './software/drivers/snappy-driver.js'; - -// Gaming -import battlenet from './software/gaming/battlenet.js'; -import eaApp from './software/gaming/ea-app.js'; -import epicGames from './software/gaming/epic-games.js'; -import gogGalaxy from './software/gaming/gog-galaxy.js'; -import hydraLauncher from './software/gaming/hydra-launcher.js'; -import retroarch from './software/gaming/retroarch.js'; -import riotClient from './software/gaming/riot-client.js'; -import steam from './software/gaming/steam.js'; -import ubisoftConnect from './software/gaming/ubisoft-connect.js'; - -// Media Creation -import audacity from './software/media-creation/audacity.js'; -import blender from './software/media-creation/blender.js'; -import gimp from './software/media-creation/gimp.js'; -import handbrake from './software/media-creation/handbrake.js'; -import inkscape from './software/media-creation/inkscape.js'; -import kdenlive from './software/media-creation/kdenlive.js'; -import obsStudio from './software/media-creation/obs-studio.js'; - -// Media Players -import aimp from './software/media-players/aimp.js'; -import appleMusic from './software/media-players/apple-music.js'; -import deezer from './software/media-players/deezer.js'; -import foobar2000 from './software/media-players/foobar2000.js'; -import itunes from './software/media-players/itunes.js'; -import mpv from './software/media-players/mpv.js'; -import spotify from './software/media-players/spotify.js'; -import tidal from './software/media-players/tidal.js'; -import vlc from './software/media-players/vlc.js'; -import winamp from './software/media-players/winamp.js'; -import youtubeMusic from './software/media-players/youtube-music.js'; - -// Productivity -import acrobatReader from './software/productivity/acrobat-reader.js'; -import evernote from './software/productivity/evernote.js'; -import libreoffice from './software/productivity/libreoffice.js'; -import notion from './software/productivity/notion.js'; -import notionCalendar from './software/productivity/notion-calendar.js'; -import obsidian from './software/productivity/obsidian.js'; -import onenote from './software/productivity/onenote.js'; -import sumatraPdf from './software/productivity/sumatra-pdf.js'; - -// Runtimes -import adobeAir from './software/runtimes/adobe-air.js'; -import directx from './software/runtimes/directx.js'; -import dotnetDesktop8 from './software/runtimes/dotnet-desktop-8.js'; -import dotnetFramework from './software/runtimes/dotnet-framework.js'; -import dotnetRuntime6 from './software/runtimes/dotnet-runtime-6.js'; -import javaJdk21 from './software/runtimes/java-jdk-21.js'; -import javaRuntime from './software/runtimes/java-runtime.js'; -import openal from './software/runtimes/openal.js'; -import openjdk21 from './software/runtimes/openjdk-21.js'; -import vcredistAll from './software/runtimes/vcredist-all.js'; -import vulkan from './software/runtimes/vulkan.js'; - -// Security -import onepassword from './software/security/1password.js'; -import bitwarden from './software/security/bitwarden.js'; -import keepassxc from './software/security/keepassxc.js'; -import lastpass from './software/security/lastpass.js'; -import malwarebytes from './software/security/malwarebytes.js'; -import nordvpn from './software/security/nordvpn.js'; -import protonvpn from './software/security/protonvpn.js'; - -// Utilities -import sevenzip from './software/utilities/7zip.js'; -import bleachbit from './software/utilities/bleachbit.js'; -import ccleaner from './software/utilities/ccleaner.js'; -import cpuZ from './software/utilities/cpu-z.js'; -import emule from './software/utilities/emule.js'; -import everything from './software/utilities/everything.js'; -import gpuZ from './software/utilities/gpu-z.js'; -import hwmonitor from './software/utilities/hwmonitor.js'; -import nero from './software/utilities/nero.js'; -import poweriso from './software/utilities/poweriso.js'; -import powertoys from './software/utilities/powertoys.js'; -import qbittorrent from './software/utilities/qbittorrent.js'; -import rainmeter from './software/utilities/rainmeter.js'; -import revoUninstaller from './software/utilities/revo-uninstaller.js'; -import sharex from './software/utilities/sharex.js'; -import ultraiso from './software/utilities/ultraiso.js'; -import winrar from './software/utilities/winrar.js'; - -export const softwareCatalog = [ - // Antivirus - avast, - avg, - bitdefender, - clamwin, - kaspersky, - - // Browsers - brave, - chrome, - chromium, - firefox, - opera, - vivaldi, - - // Cloud Storage - box, - dropbox, - googleDrive, - icloud, - mega, - protonDrive, - - // Communication - discord, - mailbird, - protonMailBridge, - signal, - slack, - teams, - telegram, - thunderbird, - whatsapp, - zoom, - - // Development - androidStudio, - cmder, - dbeaver, - dockerDesktop, - git, - githubDesktop, - insomnia, - intellijCommunity, - jetbrainsToolbox, - neovim, - nodejs, - notepadPlusplus, - postman, - putty, - pycharmCommunity, - python, - sublimeText, - terminus, - vscode, - webstorm, - - // Drivers - amdAdrenalin, - driverBooster, - driverEasy, - nvidiaGeforceExperience, - snappyDriver, - - // Gaming - battlenet, - eaApp, - epicGames, - gogGalaxy, - hydraLauncher, - retroarch, - riotClient, - steam, - ubisoftConnect, - - // Media Creation - audacity, - blender, - gimp, - handbrake, - inkscape, - kdenlive, - obsStudio, - - // Media Players - aimp, - appleMusic, - deezer, - foobar2000, - itunes, - mpv, - spotify, - tidal, - vlc, - winamp, - youtubeMusic, - - // Productivity - acrobatReader, - evernote, - libreoffice, - notion, - notionCalendar, - obsidian, - onenote, - sumatraPdf, - - // Runtimes - adobeAir, - directx, - dotnetDesktop8, - dotnetFramework, - dotnetRuntime6, - javaJdk21, - javaRuntime, - openal, - openjdk21, - vcredistAll, - vulkan, - - // Security - onepassword, - bitwarden, - keepassxc, - lastpass, - malwarebytes, - nordvpn, - protonvpn, +/** + * Process glob results into a flat array of software objects + * @returns {Array} Array of all software objects + */ +const loadSoftwareCatalog = () => { + const items = []; + + for (const path in softwareModules) { + const module = softwareModules[path]; + if (module.default) { + items.push(module.default); + } + } + + // Sort by name for consistent ordering + return items.sort((a, b) => a.name.localeCompare(b.name)); +}; - // Utilities - sevenzip, - bleachbit, - ccleaner, - cpuZ, - emule, - everything, - gpuZ, - hwmonitor, - nero, - poweriso, - powertoys, - qbittorrent, - rainmeter, - revoUninstaller, - sharex, - ultraiso, - winrar, -]; +export const softwareCatalog = loadSoftwareCatalog(); /** * Get software by category + * @param {string} categoryId - The category ID to filter by + * @returns {Array} Array of software in the specified category */ export const getSoftwareByCategory = (categoryId) => { - return softwareCatalog.filter(software => software.category === categoryId); + return softwareCatalog.filter((software) => software.category === categoryId); }; /** * Get popular software + * @returns {Array} Array of software marked as popular */ export const getPopularSoftware = () => { - return softwareCatalog.filter(software => software.popular); + return softwareCatalog.filter((software) => software.popular); }; /** * Get software by ID + * @param {string} id - The software ID to find + * @returns {Object|undefined} The software object or undefined */ export const getSoftwareById = (id) => { - return softwareCatalog.find(software => software.id === id); + return softwareCatalog.find((software) => software.id === id); };