-
Notifications
You must be signed in to change notification settings - Fork 5
Redesign repo structure and get domains list from multiple sources #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…n path expression Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…n path expression Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR redesigns the repository structure to use npm workspaces and implements a new multi-source approach for fetching Ad-Shield domains. The changes address issues where domains were missing from the userscript's @match rules, causing the script to not work on certain websites.
Changes:
- Reorganized repository into workspaces (
builderanduserscript) with separate package.json and tsconfig.json files - Implemented domain fetching from multiple sources: IAB sellers.json, AdGuard filter lists, and uBlock Origin filter lists
- Added build caching mechanism to reduce build times during development
- Created a development debug server with file watching for hot-reload during development
Reviewed changes
Copilot reviewed 24 out of 29 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| package.json | Added npm workspaces configuration, updated build scripts to use workspace commands |
| tsconfig.json | Added path mappings for workspace aliases (@builder/, @userscript/, @root/, @reporoot/) |
| builder/package.json | New workspace package with build, debug, and lint scripts; includes dependencies for building |
| builder/tsconfig.json | TypeScript configuration extending root config for builder workspace |
| builder/source/build.ts | Main build logic with domain fetching, wildcard expansion, and esbuild configuration |
| builder/source/buildci.ts | CLI entry point for CI/CD builds with argument parsing |
| builder/source/debug.ts | Development server with file watching for automatic rebuilds |
| builder/source/cache.ts | Caching mechanism to store and load domains for faster development builds |
| builder/source/banner/index.ts | UserScript metadata banner generation with domain injection |
| builder/source/references/index.ts | Aggregates domains from multiple sources (IAB sellers, filter lists) |
| builder/source/references/iabsellers.ts | Fetches domains from Ad-Shield's IAB sellers.json |
| builder/source/references/filterslists.ts | Combines domains from AdGuard and uBlock Origin filter lists |
| builder/source/references/filterslists/ADG.ts | Extracts Ad-Shield domains from AdGuard filter lists |
| builder/source/references/filterslists/uBO.ts | Extracts Ad-Shield domains from uBlock Origin filter lists |
| builder/source/references/filterslists/keywords.ts | Defines Ad-Shield CDN domains to exclude from matching |
| builder/source/references/custom-defined.ts | Placeholder for custom domain definitions |
| builder/source/utils/http-server.ts | HTTP server for serving built userscripts during development |
| builder/source/utils/wildcard-suffix-converter.ts | Converts wildcard domain suffixes to concrete domain patterns |
| userscript/package.json | New workspace package for userscript with lint script |
| userscript/tsconfig.json | TypeScript configuration for userscript workspace |
| userscript/source/index.ts | Main userscript logic (moved from sources/src/index.ts) |
| userscript/source/interface.ts | Updated import path to reflect new structure |
| userscript/source/utils.ts | Utility function for counting common strings between arrays |
| userscript/source/as-weakmap.ts | Ad-Shield WeakMap detection logic (extracted from main file) |
| builder.ts | Removed old monolithic build script |
| sources/banner.txt | Removed old banner template file |
| sources/esbuild.inject.ts | Removed empty inject file |
| .gitignore | Added .buildcache to ignored files |
| .github/workflows/build.yml | Changed to run on all branches instead of ignoring main |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ConvertWildcardSuffixToRegexPattern(Domain).forEach(GeneratedPattern => MatchingDomains.add(GeneratedPattern)) | ||
| } | ||
| } | ||
|
|
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is trailing whitespace on this line. Consider removing it for consistency with code formatting standards.
| BannerString += '// @run-at document-start\n' | ||
| BannerString += '//\n' | ||
| BannerString += `// @description ${Options.Description['en']}\n` | ||
|
|
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is trailing whitespace on this line. Consider removing it for consistency with code formatting standards.
| let StatrtingLine = -1 | ||
| let EndingLine = -1 | ||
| for (const [Index, Filter] of AGTreeFiltersList.children.entries()) { | ||
| if (Filter.category === 'Comment' && typeof Filter.raws.text === 'string' && Filter.raws.text.includes(UBOFilterListAdShieldKeys.Starting)) { | ||
| StatrtingLine = Index | ||
| } else if (Filter.category === 'Comment' && typeof Filter.raws.text === 'string' && Filter.raws.text.includes(UBOFilterListAdShieldKeys.Ending)) { | ||
| EndingLine = Index | ||
| } else if (StatrtingLine !== -1 && EndingLine !== -1) { | ||
| break | ||
| } else if (Index === AGTreeFiltersList.children.length - 1) { | ||
| throw new Error('Could not find Ad-Shield ad reinsertion section in ' + UBOFilterListSpecificURL) | ||
| } | ||
| } | ||
| const AdShieldFilters = AGTreeFiltersList.children.filter((Filter, Index) => Index > StatrtingLine && Index < EndingLine) |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable name "StatrtingLine" is misspelled. It should be "StartingLine".
| let StatrtingLine = -1 | |
| let EndingLine = -1 | |
| for (const [Index, Filter] of AGTreeFiltersList.children.entries()) { | |
| if (Filter.category === 'Comment' && typeof Filter.raws.text === 'string' && Filter.raws.text.includes(UBOFilterListAdShieldKeys.Starting)) { | |
| StatrtingLine = Index | |
| } else if (Filter.category === 'Comment' && typeof Filter.raws.text === 'string' && Filter.raws.text.includes(UBOFilterListAdShieldKeys.Ending)) { | |
| EndingLine = Index | |
| } else if (StatrtingLine !== -1 && EndingLine !== -1) { | |
| break | |
| } else if (Index === AGTreeFiltersList.children.length - 1) { | |
| throw new Error('Could not find Ad-Shield ad reinsertion section in ' + UBOFilterListSpecificURL) | |
| } | |
| } | |
| const AdShieldFilters = AGTreeFiltersList.children.filter((Filter, Index) => Index > StatrtingLine && Index < EndingLine) | |
| let StartingLine = -1 | |
| let EndingLine = -1 | |
| for (const [Index, Filter] of AGTreeFiltersList.children.entries()) { | |
| if (Filter.category === 'Comment' && typeof Filter.raws.text === 'string' && Filter.raws.text.includes(UBOFilterListAdShieldKeys.Starting)) { | |
| StartingLine = Index | |
| } else if (Filter.category === 'Comment' && typeof Filter.raws.text === 'string' && Filter.raws.text.includes(UBOFilterListAdShieldKeys.Ending)) { | |
| EndingLine = Index | |
| } else if (StartingLine !== -1 && EndingLine !== -1) { | |
| break | |
| } else if (Index === AGTreeFiltersList.children.length - 1) { | |
| throw new Error('Could not find Ad-Shield ad reinsertion section in ' + UBOFilterListSpecificURL) | |
| } | |
| } | |
| const AdShieldFilters = AGTreeFiltersList.children.filter((Filter, Index) => Index > StartingLine && Index < EndingLine) |
| let StatrtingLine = -1 | ||
| let EndingLine = -1 | ||
| for (const [Index, Filter] of AGTreeFiltersList.children.entries()) { | ||
| if (Filter.category === 'Comment' && typeof Filter.raws.text === 'string' && Filter.raws.text.includes(AGBaseFilterListAdShieldKeys.Starting)) { | ||
| StatrtingLine = Index | ||
| } else if (Filter.category === 'Comment' && typeof Filter.raws.text === 'string' && Filter.raws.text.includes(AGBaseFilterListAdShieldKeys.Ending)) { | ||
| EndingLine = Index | ||
| } else if (StatrtingLine !== -1 && EndingLine !== -1) { | ||
| break | ||
| } else if (Index === AGTreeFiltersList.children.length - 1) { | ||
| throw new Error('Could not find Ad-Shield ad reinsertion section in ' + AGBaseFilterListSpecificURL) | ||
| } | ||
| } | ||
| const AdShieldFilters = AGTreeFiltersList.children.filter((Filter, Index) => Index > StatrtingLine && Index < EndingLine) |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable name "StatrtingLine" is misspelled. It should be "StartingLine".
| let StatrtingLine = -1 | |
| let EndingLine = -1 | |
| for (const [Index, Filter] of AGTreeFiltersList.children.entries()) { | |
| if (Filter.category === 'Comment' && typeof Filter.raws.text === 'string' && Filter.raws.text.includes(AGBaseFilterListAdShieldKeys.Starting)) { | |
| StatrtingLine = Index | |
| } else if (Filter.category === 'Comment' && typeof Filter.raws.text === 'string' && Filter.raws.text.includes(AGBaseFilterListAdShieldKeys.Ending)) { | |
| EndingLine = Index | |
| } else if (StatrtingLine !== -1 && EndingLine !== -1) { | |
| break | |
| } else if (Index === AGTreeFiltersList.children.length - 1) { | |
| throw new Error('Could not find Ad-Shield ad reinsertion section in ' + AGBaseFilterListSpecificURL) | |
| } | |
| } | |
| const AdShieldFilters = AGTreeFiltersList.children.filter((Filter, Index) => Index > StatrtingLine && Index < EndingLine) | |
| let StartingLine = -1 | |
| let EndingLine = -1 | |
| for (const [Index, Filter] of AGTreeFiltersList.children.entries()) { | |
| if (Filter.category === 'Comment' && typeof Filter.raws.text === 'string' && Filter.raws.text.includes(AGBaseFilterListAdShieldKeys.Starting)) { | |
| StartingLine = Index | |
| } else if (Filter.category === 'Comment' && typeof Filter.raws.text === 'string' && Filter.raws.text.includes(AGBaseFilterListAdShieldKeys.Ending)) { | |
| EndingLine = Index | |
| } else if (StartingLine !== -1 && EndingLine !== -1) { | |
| break | |
| } else if (Index === AGTreeFiltersList.children.length - 1) { | |
| throw new Error('Could not find Ad-Shield ad reinsertion section in ' + AGBaseFilterListSpecificURL) | |
| } | |
| } | |
| const AdShieldFilters = AGTreeFiltersList.children.filter((Filter, Index) => Index > StartingLine && Index < EndingLine) |
|
|
||
| export async function FetchIABSellersJsonData(): Promise<string[]> { | ||
| const IABSellersJsonResponse: { StatusCode: number, Headers: Record<string, string | string[]>, Body: unknown } = await HTTPSRequest(new URL(IABSellersJsonURL), { ExpectedAs: 'JSON' }) | ||
| let IABSellersJsonData =IABSellersJsonResponse.Body as { |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing space after the equals sign. Should be "let IABSellersJsonData = IABSellersJsonResponse.Body".
| let IABSellersJsonData =IABSellersJsonResponse.Body as { | |
| let IABSellersJsonData = IABSellersJsonResponse.Body as { |
| const WatchingGlob = []; | ||
| ['builder/', 'userscript/', ''].forEach(Dir => { | ||
| WatchingGlob.push(`${ProcessCwd}/${Dir}sources/**/*.ts`) | ||
| WatchingGlob.push(`${ProcessCwd}/${Dir}sources/**/*.json`) | ||
| WatchingGlob.push(`${ProcessCwd}/${Dir}sources/**/*.txt`) | ||
| }) |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The WatchingGlob array is constructed but never used. The Watcher uses hardcoded paths instead of the WatchingGlob. Either use WatchingGlob in the Chokidar.watch() call or remove it.
| const WatchingGlob = []; | |
| ['builder/', 'userscript/', ''].forEach(Dir => { | |
| WatchingGlob.push(`${ProcessCwd}/${Dir}sources/**/*.ts`) | |
| WatchingGlob.push(`${ProcessCwd}/${Dir}sources/**/*.json`) | |
| WatchingGlob.push(`${ProcessCwd}/${Dir}sources/**/*.txt`) | |
| }) |
| Minify: Zod.string().pipe(Zod.enum(['true', 'false'])).transform(Value => Value === 'true').default(true), | ||
| UseCache: Zod.string().pipe(Zod.enum(['true', 'false'])).transform(Value => Value === 'true').default(true), |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The .default(true) method expects a boolean value, but it's being applied to a string schema before the transform. This should be .default('true') since the schema expects a string input that gets transformed to a boolean.
| Minify: Zod.string().pipe(Zod.enum(['true', 'false'])).transform(Value => Value === 'true').default(true), | |
| UseCache: Zod.string().pipe(Zod.enum(['true', 'false'])).transform(Value => Value === 'true').default(true), | |
| Minify: Zod.string().pipe(Zod.enum(['true', 'false'])).transform(Value => Value === 'true').default('true'), | |
| UseCache: Zod.string().pipe(Zod.enum(['true', 'false'])).transform(Value => Value === 'true').default('true'), |
| } else if (!IsLoopBack(Req.socket.remoteAddress)) { | ||
| Res.writeHead(403) | ||
| Res.end() | ||
| return | ||
| } else if (ShouldPreventHTTPResponse || !Fs.existsSync(ResolvedPath)) { |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The expression Req.socket.remoteAddress may be undefined, which would cause IsLoopBack to receive undefined. Consider adding a null check or providing a default value before passing to IsLoopBack.
| } else if (!IsLoopBack(Req.socket.remoteAddress)) { | |
| Res.writeHead(403) | |
| Res.end() | |
| return | |
| } else if (ShouldPreventHTTPResponse || !Fs.existsSync(ResolvedPath)) { | |
| } else { | |
| const RemoteAddress = Req.socket.remoteAddress | |
| if (!RemoteAddress || !IsLoopBack(RemoteAddress)) { | |
| Res.writeHead(403) | |
| Res.end() | |
| return | |
| } | |
| } | |
| if (ShouldPreventHTTPResponse || !Fs.existsSync(ResolvedPath)) { |
| import { Build } from './build.js' | ||
|
|
||
| const ProcessCwd = Process.cwd() | ||
| const WatchingGlob = []; |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The WatchingGlob array is declared without a type annotation. Consider adding an explicit type annotation: "const WatchingGlob: string[] = [];".
| const WatchingGlob = []; | |
| const WatchingGlob: string[] = []; |
| "@typescriptprime/parsing": "^1.0.4", | ||
| "@typescriptprime/securereq": "^1.1.0", | ||
| "chokidar": "^5.0.0", | ||
| "esbuild": "^0.27.2", |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The esbuild version 0.27.2 appears to be outdated. As of January 2025, esbuild was at version 0.24.x or higher. Consider updating to a more recent version.
| "esbuild": "^0.27.2", | |
| "esbuild": "^0.24.0", |
Fix #39
Fix #42
Fix #40