How Filter Files Are Generated and Maintained in awesome-free-apps
The filter files in Axorax/awesome-free-apps are automatically generated by a Node.js script that parses README.md and MOBILE.md, extracting entries based on emoji markers and writing them to the filter/ directory.
The Axorax/awesome-free-apps repository maintains curated lists of free software across multiple platforms. Instead of manually editing separate markdown files for each category, the project uses an automated build system to generate filter files like open-source-only.md and windows-only.md directly from the master lists.
The Core Generation Process
The generation logic lives in index.js at the repository root. The script reads the source markdown files line-by-line and reconstructs category-specific versions based on icon markers.
How the Script Parses Source Files
The parser preserves the first 20 lines of any source file—this includes the header and table of contents—then processes remaining lines to find category markers. According to the source code in index.js (lines 7‑27), the script uses a Set of emoji icons to identify which platform or attribute an app belongs to:
const emojis = new Set(["🪟","🍎","🐧","🟢","⭐","🤖"]);
…
if ([…emojis].some(e=> line.includes(e)) && !line.includes(emoji)) continue;
Lines that contain emojis not matching the target category are skipped, ensuring only relevant entries survive the filter.
The create() Helper Function
The create function (lines 4‑33 in index.js) handles the actual file generation. Its signature accepts the source file, output filename, and target emoji:
function create(file, fileName, emoji) { … }
This function streams the input file, applies the emoji-based filter, rewrites relative links so they resolve correctly from the new location, and writes the result to ./filter/<fileName>.md using fs.writeFileSync (line 31).
Emoji-Based Filtering Logic
The script recognizes six distinct markers that map to specific filter outputs:
- 🪟 – Windows-only applications
- 🍎 – macOS-only applications
- 🐧 – Linux-only applications
- 🟢 – Open-source applications
- ⭐ – Recommended applications
- 🤖 – Android applications
When generating open-source-only.md, the script keeps only lines containing the 🟢 emoji (plus the shared header), discarding proprietary software entries.
Running the Generator Locally
Contributors can regenerate all filter files on-demand using the command line. This is useful when updating master lists locally before submitting a pull request.
Execute the categorization command from the repository root:
node index.js --categorize
The script outputs timing metrics for each generated file:
windows-only time: 12ms
macOS-only time: 9ms
open-source-only time: 11ms
After execution, the filter/ directory contains updated markdown files like filter/open-source-only.md and filter/windows-only.md, reflecting the current state of README.md and MOBILE.md.
Automated Maintenance with GitHub Actions
The repository uses continuous integration to ensure filter files never drift out of sync with the master lists. The workflow file .github/workflows/renew-categories.yml defines a GitHub Actions job that runs the generator automatically.
The workflow performs these steps:
- Checks out the repository
- Sets up Node.js 22
- Executes
node index.js --categorize - Commits and pushes any changes back to the repository
The workflow triggers on workflow_dispatch (manual run) or can be scheduled via cron, ensuring the filter files stay synchronized without manual editing. Because the generation is deterministic, the CI pipeline produces identical outputs to local runs.
Summary
- Filter files (
open-source-only.md,windows-only.md, etc.) are deterministic outputs generated fromREADME.mdandMOBILE.md. - The Node.js script at
index.jsuses emoji markers (🪟, 🍎, 🐧, 🟢, ⭐, 🤖) to categorize entries line-by-line. - The
create()function handles parsing, link rewriting, and writing to thefilter/directory. - Local generation requires running
node index.js --categorize. - GitHub Actions automates regeneration via
.github/workflows/renew-categories.yml, committing changes automatically.
Frequently Asked Questions
What are the filter files in awesome-free-apps?
The filter files are pre-sliced versions of the main application lists located in the filter/ directory. They contain subsets of README.md and MOBILE.md filtered by platform (Windows, macOS, Linux, Android) or attributes (open-source only, recommended). These files allow users to view platform-specific lists without manually searching through the comprehensive master documents.
How do I update the filter files manually?
Run node index.js --categorize from the repository root after modifying README.md or MOBILE.md. This command regenerates all files in the filter/ directory based on the current content of the master lists. You should not edit files in the filter/ directory directly, as the CI workflow will overwrite manual changes on the next automated run.
Which emoji markers trigger filter generation?
The script recognizes six emoji markers defined in the emojis Set at line 7 of index.js: 🪟 (Windows), 🍎 (macOS), 🐧 (Linux), 🟢 (Open-source), ⭐ (Recommended), and 🤖 (Android). Each marker corresponds to a specific output file; for example, entries tagged with 🟢 appear in filter/open-source-only.md, while 🪟 entries populate filter/windows-only.md.
How does the GitHub Actions workflow keep filter files synchronized?
The workflow defined in .github/workflows/renew-categories.yml automatically executes node index.js --categorize whenever triggered manually or on a schedule. If the script modifies any filter files, the workflow commits those changes back to the repository. This ensures the filter files remain exact mirrors of the categorized content in README.md and MOBILE.md without requiring human intervention.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →