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
7 changes: 2 additions & 5 deletions .github/workflows/lint-and-typecheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,8 @@ jobs:
- name: Install dependencies
run: bun install --frozen-lockfile

- name: Check Prettier
run: bun run format

- name: Check ESLint
run: bun run lint
- name: Check Biome (lint + format)
run: bunx @biomejs/biome ci .

- name: Build (required for tsc)
run: bun run build
Expand Down
16 changes: 0 additions & 16 deletions .prettierignore

This file was deleted.

10 changes: 0 additions & 10 deletions .prettierrc

This file was deleted.

20 changes: 10 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ All commands use Bun. Run from the repo root:
bun install # Install all dependencies (uses Bun workspaces)
bun run build # Build all packages (ESM, CommonJS, MJS, browser)
bun run test # Run all tests (Vitest, headless Chromium via Playwright)
bun run lint # Run ESLint
bun run lint:fix # Run ESLint with auto-fix
bun run format # Check Prettier formatting
bun run format:fix # Fix Prettier formatting
bun run check # Run Biome (lint + format)
bun run lint # Run Biome lint only
bun run lint:fix # Run Biome lint with auto-fix
bun run format # Check Biome formatting
bun run format:fix # Fix Biome formatting
bun run tsc # TypeScript type-check (no emit)
bun run dts # Generate TypeScript declaration files
bun run clean # Clean dist/ and coverage/ dirs
Expand All @@ -62,12 +63,11 @@ because TKO does low-level DOM manipulation, MutationObserver, and event handlin

## Code Style

- **Formatter**: Prettier — no semicolons, single quotes, trailing commas: none, 120 char width
- **Linter**: ESLint with typescript-eslint (flat config)
- **Editor**: 2-space indentation for JS/TS, LF line endings
- See `.prettierrc` and `eslint.config.js` for full config
- **Linter + Formatter**: Biome — single Rust-native tool replacing ESLint + Prettier
- **Style**: no semicolons, single quotes, trailing commas: none, 120 char width, 2-space indent, LF line endings
- See `biome.json` for full config

Run `bun run format:fix && bun run lint:fix` before committing.
Run `bun run lint:fix` before committing.

## TypeScript

Expand Down Expand Up @@ -102,7 +102,7 @@ GitHub Actions workflows (`.github/workflows/`):
|----------|---------|---------|
| `main-build.yml` | Push to main | Build + audit + headless test |
| `test-headless.yml` | PRs | Matrix test (Chrome, Firefox, jQuery) |
| `lint-and-typecheck.yml` | PRs | Prettier + ESLint + tsc (combined) |
| `lint-and-typecheck.yml` | PRs | Biome + tsc (lint, format, typecheck) |
| `publish-check.yml` | PRs | Verify packages are publishable |
| `release.yml` | Tag push (`v*`) | Changeset version PRs + npm publish + GitHub release creation |
| `github-release.yml` | Manual fallback | Backfill a GitHub release/tag for a published `main` commit if automatic release creation needs a retry |
Expand Down
76 changes: 76 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.11/schema.json",
"vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
"files": {
"ignoreUnknown": true,
"includes": ["packages/**", "builds/**", "tools/**", "global.d.ts", "vitest.config.ts"]
},
Comment on lines +4 to +7
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

files.includes restricts Biome to only packages/**, builds/**, and global.d.ts, which is a narrower scope than the current prettier . / eslint . scripts (e.g., it would exclude tools/build.ts and root config .ts files). If the goal is a full ESLint+Prettier replacement, expand this include list (or remove it) so biome format/biome ci covers the same files as today.

Copilot uses AI. Check for mistakes.
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 120,
"lineEnding": "lf"
},
"linter": {
"enabled": true,
"includes": ["**/*.ts"],
"rules": {
"recommended": true,
"complexity": {
"noUselessEscapeInRegex": "off",
"noArguments": "off",
"noBannedTypes": "off",
"useArrowFunction": "off",
"noThisInStatic": "off"
},
"correctness": {
Comment on lines +18 to +27
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

The plan/PR description calls out turning off several unfixable rules for parity (e.g. noArguments, noImplicitAnyLet, noUnusedFunctionParameters, noGlobalEval, noNonNullAssertion, noThisInStatic), but they are not disabled in this linter.rules config. If those rules are enabled by recommended: true, biome ci will still fail/noise; please add explicit "off" entries (or update the plan if it’s outdated).

Copilot uses AI. Check for mistakes.
"noUnusedVariables": "warn",
"noUnusedImports": "warn",
"noUnusedFunctionParameters": "warn"
},
"style": {
"useConst": "off",
"useArrayLiterals": "off",
"noNamespace": "off",
"noNonNullAssertion": "off"
},
"suspicious": {
"noExplicitAny": "off",
"noAssignInExpressions": "off",
"noMisleadingCharacterClass": "off",
"noDoubleEquals": "off",
"noRedeclare": "error",
"noShadowRestrictedNames": "off",
"noControlCharactersInRegex": "off",
"noEmptyBlockStatements": "off",
"noPrototypeBuiltins": "off",
"noFallthroughSwitchClause": "error",
"noImplicitAnyLet": "off",
"noTemplateCurlyInString": "off",
"useIterableCallbackReturn": "off",
"noGlobalIsNan": "off",
"noGlobalIsFinite": "off",
"noThenProperty": "off",
"useGetterReturn": "error"
},
"performance": {
"noDelete": "off"
},
"security": {
"noGlobalEval": "off"
}
}
},
"javascript": {
"formatter": {
"semicolons": "asNeeded",
"trailingCommas": "none",
"quoteStyle": "single",
"arrowParentheses": "asNeeded"
}
},
"assist": {
"enabled": false
}
}
27 changes: 21 additions & 6 deletions builds/knockout/helpers/mocha-test-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@ function detectIEVersion() {
const div = document.createElement('div')
const iElems = div.getElementsByTagName('i')

while ((div.innerHTML = '<!--[if gt IE ' + ++version + ']><i></i><![endif]-->'), iElems[0]) {}
while (((div.innerHTML = '<!--[if gt IE ' + ++version + ']><i></i><![endif]-->'), iElems[0])) {}
return version > 4 ? version : undefined
}

function expectEqualOneOf(actual, expectedPossibilities) {
const matches = expectedPossibilities.some(function (expected) { return chai.util.eql(actual, expected) })
const matches = expectedPossibilities.some(function (expected) {
return chai.util.eql(actual, expected)
})
expect(matches, 'expected value to deeply equal one of the provided possibilities').to.equal(true)
}

Expand Down Expand Up @@ -93,18 +95,31 @@ function expectHaveTexts(actual, expectedTexts) {
}

function expectHaveValues(actual, expectedValues) {
const values = ko.utils.arrayFilter(ko.utils.arrayMap(actual.childNodes, function (node) { return node.value }), function (value) { return value !== undefined })
const values = ko.utils.arrayFilter(
ko.utils.arrayMap(actual.childNodes, function (node) {
return node.value
}),
function (value) {
return value !== undefined
}
)
expect(values).to.deep.equal(expectedValues)
}

function expectHaveCheckedStates(actual, expectedValues) {
const values = ko.utils.arrayMap(actual.childNodes, function (node) { return node.checked })
const values = ko.utils.arrayMap(actual.childNodes, function (node) {
return node.checked
})
expect(values).to.deep.equal(expectedValues)
}

function expectHaveSelectedValues(actual, expectedValues) {
const selectedNodes = ko.utils.arrayFilter(actual.childNodes, function (node) { return node.selected })
const selectedValues = ko.utils.arrayMap(selectedNodes, function (node) { return ko.selectExtensions.readValue(node) })
const selectedNodes = ko.utils.arrayFilter(actual.childNodes, function (node) {
return node.selected
})
const selectedValues = ko.utils.arrayMap(selectedNodes, function (node) {
return ko.selectExtensions.readValue(node)
})
expect(selectedValues).to.deep.equal(expectedValues)
}

Expand Down
Loading
Loading