Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
75 changes: 35 additions & 40 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ minified JavaScript bookmarklets.
- **Target Runtime**: Browser bookmarklets (ES2020)
- **Build Tools**: TypeScript compiler, Terser for minification, Node.js
scripts
- **Lines of Code**: 16 TypeScript source files in `src/`, 5 Node.js scripts
- **Lines of Code**: 21 TypeScript source files in `src/`, 6 Node.js scripts
in `scripts/`
- **Node Version Required**: >=24.12.0 (strict requirement via
- **Node Version Required**: >=24.13.1 (strict requirement via
`engineStrict: true`)
- **npm Version Required**: >=11.6.0
- **Primary Output**: 16 `.bookmarklet` files in `dist/` directory
- **npm Version Required**: >=11.8.0
- **Primary Output**: 21 `.bookmarklet` files in `dist/` directory

## Critical Build Instructions

Expand Down Expand Up @@ -71,7 +71,7 @@ npm test

This runs `npm run build && npm run verify-build`. The verification ensures:

- All 16 bookmarklets were built
- All 21 bookmarklets were built
- Calculates total size
- **Expected time**: 5-10 seconds

Expand Down Expand Up @@ -106,10 +106,10 @@ cp -fpv pre-push .git/hooks

### Linting

ESLint configuration is in `.github/linters/eslint.config.js`:
ESLint configuration is in `eslint.config.js` (project root, auto-discovered):

```bash
npx eslint --config .github/linters/eslint.config.js .
npx eslint .
```

**Expected time**: 2-5 seconds
Expand All @@ -129,40 +129,42 @@ file with current bookmarklet code.

### Source Files

- **`src/*.ts`** - 16 TypeScript bookmarklet source files (human-readable)
- **`src/*.ts`** - 21 TypeScript bookmarklet source files (human-readable)
- Each file is a self-contained bookmarklet implementation
- Uses strict TypeScript configuration (see `tsconfig.json`)
- Target: ES2020 for modern browser compatibility

- **`scripts/*.js`** - 5 Node.js build scripts:
- **`scripts/*.js`** - 6 Node.js build/test scripts:
- `build-bookmarklet.js` - Converts minified JS to bookmarklet URLs
- `minify.js` - Minifies compiled JavaScript with Terser
- `test-utmstrip.js` - UTM strip parameter test suite
- `update-readme.js` - Updates README.md with bookmarklet links
- `verify-build.js` - Validates build output
- `utils.js` - Shared utilities

### Build Artifacts

- **`.temp/*.js`** - TypeScript compiler output (intermediate, gitignored)
- **`dist/*.bookmarklet`** - Final bookmarklet files (16 files, committed to git)
- **`dist/*.bookmarklet`** - Final bookmarklet files (21 files, committed to git)

**CRITICAL**: Never examine or review the contents of `dist/*.bookmarklet`
files. These are URL-encoded bookmarklets, not TypeScript or JavaScript. They
start with `javascript:` and contain percent-encoded minified code. **The only
validation needed is that for every `src/*.ts` file basename, there exists
exactly one corresponding `dist/*.bookmarklet` file.** Use `npm run
verify-build` to check this automatically.
exactly one corresponding `dist/*.bookmarklet` file (plus any listed in
`bookmarklets.json`).** Use `npm run verify-build` to check this
automatically.

### Configuration Files

- **`package.json`** - Dependencies and npm scripts
- **`tsconfig.json`** - TypeScript compiler configuration (src/)
- **`tsconfig.scripts.json`** - TypeScript configuration for scripts (unused currently)
- **`bookmarklets.json`** - Bookmarklet metadata (name, file, version)
- **`.github/linters/eslint.config.js`** - ESLint rules (strict, security-focused)
- **`.github/linters/.markdownlint.json`** - Markdown linting rules
- **`.github/linters/.yaml-lint.yml`** - YAML linting rules
- **`.github/linters/actionlint.yaml`** - GitHub Actions linting rules
- **`eslint.config.js`** - ESLint rules (strict, security-focused)
- **`.markdownlint.json`** - Markdown linting rules
- **`.yamllint.yml`** - YAML linting rules
- **`.github/actionlint.yaml`** - GitHub Actions linting rules
- **`.cspell.jsonc`** - Spell checking configuration
- **`.cspell/dictionary-custom.txt`** - Custom word dictionary

Expand All @@ -174,14 +176,11 @@ Located in `.github/workflows/`:
- Triggers: push to main/hotfix, PRs to main
- Matrix: Node 24.x and 25.x
- Steps: Security audit → Install deps → Build & test → Generate SBOM
- **Note**: Security audit currently has `continue-on-error: true` until
Dec 18, 2025 (js-yaml issue)
- **Timeout**: 5 minutes

2. **`linter.yml`** - Lint Code Base
- Triggers: push to main/hotfix, PRs to main, manual dispatch
- Runs: ESLint + Super-Linter (Bash, GitHub Actions, JSON, JSONC, Markdown,
YAML)
- Runs: ESLint, markdownlint, yamllint, JSON/JSONC validation
- **Timeout**: 10 minutes
- Excludes: `dist/*.bookmarklet` files from linting

Expand Down Expand Up @@ -230,24 +229,12 @@ Check that builds still work after updates.

## Known Issues and Workarounds

### npm Audit Warnings (Temporary)

**Issue**: npm audit may report moderate vulnerabilities in js-yaml transitive
dependency.

**Workaround**: Currently set to `continue-on-error: true` in workflows until
December 18, 2025, or until js-yaml is updated. This is documented in:

- `.github/workflows/ci.yml` (line 39)
- `.github/workflows/release.yml` (line 47)
- `pre-push` script (line 50)

### Node Version Mismatch Warnings

**Issue**: If you see `EBADENGINE Unsupported engine` warnings:

```text
npm warn EBADENGINE required: { node: '>=24.12.0', npm: '>=11.6.0' }
npm warn EBADENGINE required: { node: '>=24.13.1', npm: '>=11.8.0' }
npm warn EBADENGINE current: { node: 'v20.19.6', npm: '10.8.2' }
```

Expand All @@ -271,8 +258,9 @@ cp -fpv pre-push .git/hooks
**Issue**: preflight skips checks if optional tools (shellcheck, yamllint,
actionlint, cspell) aren't installed.

**Workaround**: These checks are non-blocking locally but will run in CI.
Install tools for full validation:
**Workaround**: These are optional local checks. yamllint and markdownlint
also run in CI; shellcheck and actionlint are local-only. Install tools for
full local validation:

```sh
# shellcheck
Expand Down Expand Up @@ -308,8 +296,9 @@ npm install -g cspell
- `src/` - TypeScript bookmarklet source files (16 files)
- `scripts/` - Node.js build scripts (5 files)
- `dist/` - Built bookmarklet files (16 .bookmarklet files)
- `.github/workflows/` - CI/CD workflows (4 files)
- `.github/linters/` - Linting configurations (4 files)
- `.github/workflows/` - CI/CD workflows (5 files)
- Root linter configs: `eslint.config.js`, `.markdownlint.json`, `.yamllint.yml`
- `.github/actionlint.yaml` - GitHub Actions linting rules
- `.cspell/` - Spell check dictionary
- `.temp/` - Temporary build artifacts (gitignored)
- `node_modules/` - Dependencies (gitignored)
Expand Down Expand Up @@ -339,8 +328,14 @@ npm install -g cspell
8. **ESLint is strict**. The configuration enforces security rules and strict
coding standards. If eslint fails, fix the issues - don't disable rules.

9. **Super-Linter runs in CI**. Local preflight may skip some checks if tools
are missing, but CI runs all checks.
9. **Linter configs use convention over configuration.** `eslint.config.js`,
`.markdownlint.json`, and `.yamllint.yml` are in the project root where
their tools auto-discover them. Do not add explicit `--config` flags —
the default discovery is intentional.

10. **CI runs individual linters** (ESLint, markdownlint, yamllint, JSON/JSONC
validation) directly on the Ubuntu runner — no Docker or Super-Linter.
actionlint runs locally only (via `preflight`).

10. **GitHub Actions run automatically** on push/PR. Check workflow results if
11. **GitHub Actions run automatically** on push/PR. Check workflow results if
CI fails.
61 changes: 31 additions & 30 deletions .github/workflows/linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,58 +10,59 @@ on:

permissions:
contents: read
statuses: write

# Prevent concurrent runs for the same PR/branch
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
lint:
name: "Lint Code Base"
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
# Checkout the code base
- name: "Checkout Code"
uses: actions/checkout@v6
with:
# Full git history needed to get list of changed files w/in `super-linter`
fetch-depth: 0

# Setup Node.js with cache
- name: "Setup Node.js"
uses: actions/setup-node@v6
with:
node-version: '24.x'
cache: 'npm'

# install
- name: "Install Dependencies"
run: npm ci --prefer-offline

# Run project's ESLint
- name: "Run ESLint"
run: npx eslint --config .github/linters/eslint.config.js .
- name: "Run ESLint"
run: npx eslint .

- name: "Lint Markdown"
run: npx markdownlint-cli2 "**/*.md" "#node_modules" "#dist"
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Markdown linting is run via markdownlint-cli2, but no explicit configuration is provided. Since this PR adds .markdownlint.json with custom rules, consider ensuring the workflow actually loads that config (otherwise the new rules may not be enforced).

Suggested change
run: npx markdownlint-cli2 "**/*.md" "#node_modules" "#dist"
run: npx markdownlint-cli2 -c .github/linters/.markdownlint.json "**/*.md" "#node_modules" "#dist"

Copilot uses AI. Check for mistakes.

- name: "Lint YAML"
run: |
pip install --quiet yamllint
yamllint .
Comment on lines +46 to +47
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

YAML linting installs an unpinned yamllint version and runs it without specifying the repo config. For reproducible CI and to ensure .yamllint.yml rules/ignores are applied, consider pinning the yamllint version and invoking it with -c .yamllint.yml.

Suggested change
pip install --quiet yamllint
yamllint .
pip install --quiet yamllint==1.35.1
yamllint -c .github/linters/.yaml-lint.yml .

Copilot uses AI. Check for mistakes.

- name: "Validate JSON"
run: |
find . -name '*.json' \
-not -path './node_modules/*' \
-not -path './.git/*' \
-not -path './dist/*' \
-print0 | xargs -0 -I{} node -e \
"JSON.parse(require('fs').readFileSync('{}','utf8'))"

# Run Linter against code base
- name: Super-linter
uses: super-linter/super-linter/slim@v8
env:
ACTIONS_RUNNER_DEBUG: false
DEFAULT_BRANCH: main
FILTER_REGEX_EXCLUDE: dist\/.*\. bookmarklet
GITHUB_TOKEN: ${{ secrets. GITHUB_TOKEN }}
LOG_LEVEL: NOTICE
SUPPRESS_POSSUM: true
VALIDATE_ALL_CODEBASE: true
# Only validate these specific things
VALIDATE_BASH: true
VALIDATE_BASH_EXEC: true
VALIDATE_GITHUB_ACTIONS: true
VALIDATE_JSON: true
VALIDATE_JSONC: true
VALIDATE_MARKDOWN: true
VALIDATE_YAML: true
- name: "Validate JSONC"
run: |
node -e "
const fs = require('fs');
const c = fs.readFileSync('.cspell.jsonc','utf8')
.replace(/\/\/.*$/gm,'')
.replace(/\/\*[\s\S]*?\*\//g,'')
.replace(/,(\s*[}\]])/g,'\$1');
JSON.parse(c);
console.log('.cspell.jsonc: valid');
"
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Now some make or modify URLs, or determine if a site is hosted on AWS.

![version](https://img.shields.io/github/package-json/v/mobilemind/OpenInlets.svg)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/1db800475a4744c68fe643a84a4454f4)](https://www.codacy.com/gh/mobilemind/OpenInlets/dashboard?utm_source=github.com&utm_medium=referral&utm_content=mobilemind/OpenInlets&utm_campaign=Badge_Grade)
[![GitHub Super-Linter](https://github.com/mobilemind/OpenInlets/actions/workflows/linter.yml/badge.svg)](https://github.com/mobilemind/OpenInlets/actions/workflows/linter.yml)
[![Lint Code Base](https://github.com/mobilemind/OpenInlets/actions/workflows/linter.yml/badge.svg)](https://github.com/mobilemind/OpenInlets/actions/workflows/linter.yml)
[![CodeQL](https://github.com/mobilemind/OpenInlets/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/mobilemind/OpenInlets/actions/workflows/codeql-analysis.yml)
[![NodeJS Build](https://github.com/mobilemind/OpenInlets/actions/workflows/ci.yml/badge.svg)](https://github.com/mobilemind/OpenInlets/actions/workflows/ci.yml)

Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ the source files where the code is readable and parseable.

### Security Configuration

ESLint security rules enabled in `.github/linters/eslint.config.js`:
ESLint security rules enabled in `eslint.config.js`:

- `eslint-plugin-security` with recommended rules
- No `eval()` or implied eval allowed
Expand Down
2 changes: 1 addition & 1 deletion .github/linters/eslint.config.js → eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ module.exports = [
}
},
{
files: ["scripts/*.js", ".github/linters/*.js"],
files: ["scripts/*.js"],
ignores: [".cspell.json","*.json", "**/*{.,-}min.js", "node_modules/*", "dist/*.bookmarklet"],
languageOptions: {
ecmaVersion: 2023,
Expand Down
Loading
Loading