Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
10 changes: 5 additions & 5 deletions .github/workflows/js-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ on:
- 'bun.lock'
- 'biome.json'
- 'tsconfig.json'
- '.github/workflows/js-lint.yml'
pull_request:
paths:
- '**/*.js'
Expand All @@ -21,14 +22,15 @@ on:
- 'bun.lock'
- 'biome.json'
- 'tsconfig.json'
- '.github/workflows/js-lint.yml'
workflow_dispatch:

permissions:
contents: read

jobs:
lint:
name: Biome + TypeScript
frontend:
name: Biome + TypeScript + Bun tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
Expand All @@ -37,6 +39,4 @@ jobs:

- run: bun install --frozen-lockfile

- run: bun run lint

- run: bunx tsc --noEmit
- run: bun run check:frontend
Comment thread
coderabbitai[bot] marked this conversation as resolved.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# TekstTV (WordPress plugin)

WordPress plugin to manage text-TV slides and serve them as JSON to the [TekstTV playout app](https://github.com/oszuidwest/teksttv-frontend). In the Tekst TV admin menu you set up channels, build the broadcast loop from blocks (posts, images, iframes, campaigns, weather, ticker items), and manage settings, campaigns and optional AI-assisted content.
Expand Down Expand Up @@ -77,8 +77,11 @@
|--------------------|---------|
| `bun run build` | Minify JS/CSS to `assets/`, copy TinyMCE and tom-select vendor files |
| `bun run dev` | Watch JS and CSS |
| `bun run lint` | PHPCS + Biome on `resources/` |
| `bun run check` | PHPCS plus all frontend checks |
| `bun run check:frontend` | Biome, TypeScript and Bun unit tests |
| `bun run lint` | Biome on maintained JS, TS and CSS sources/tests |
| `bun run lint:fix` | PHPCBF + Biome `--write` |
| `bun run typecheck`| TypeScript type checking without emitting files |
| `bun run analyse` | PHPStan |
| `bun run test` | PHPUnit (unit) |
| `bun run env:start`| Build + package the artifact and boot WordPress via [`wp-env`](https://www.npmjs.com/package/@wordpress/env) (needs Docker) |
Expand Down
15 changes: 12 additions & 3 deletions biome.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.9/schema.json",
"$schema": "https://biomejs.dev/schemas/2.5.5/schema.json",
"files": {
"includes": ["**/resources/ts/**/*.ts"]
"includes": [
"resources/**/*.ts",
"resources/**/*.js",
"resources/**/*.css",
"tests/**/*.ts",
"tests/**/*.js",
"playwright.config.ts"
]
},
Comment on lines +4 to 5

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Files:"
git ls-files | sed -n '1,200p'

echo
echo "biome.json:"
if [ -f biome.json ]; then cat -n biome.json | sed -n '1,220p'; fi

echo
echo "Search for files.includes / lint / check:"
rg -n '"files"|"includes"|"biome check"|lint|formatter' -S . --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' | sed -n '1,240p'

Repository: oszuidwest/teksttv-wp-plugin

Length of output: 8170


🌐 Web query:

Biome configuration files includes files includes configuration files biome check does not lint included linter rules

💡 Result:

In Biome, the files.includes and tool-specific .includes (such as linter.includes) fields determine which files are processed [1][2]. The statement that "biome check does not lint included linter rules" is not a standard or documented behavior of Biome, but users may encounter issues where files or rules appear ignored due to configuration order, glob syntax, or specific environment factors [3][4][5]. Key points regarding Biome's include/exclude configuration: 1. Relationship between files.includes and linter.includes: The global files.includes setting is the primary filter. If a file is not matched by files.includes, it is excluded from all Biome operations, including linting [6]. Consequently, a tool-specific include setting (like linter.includes) cannot include a file that has already been excluded by files.includes [2][6]. 2. Configuration Precedence and Overrides: Settings are hierarchical. If you are not seeing expected linting behavior, ensure that your glob patterns are correctly defined relative to the configuration file [2][7]. Additionally, there have been confirmed bug reports regarding inconsistent behavior with linter.includes in monorepo setups or when using specific CLI flags like --staged [3][5]. 3. Glob Pattern Requirements: When using negated patterns (e.g., !file.js) to exclude files, you must generally specify a base glob like `` first to ensure all files are initially considered [1][2]. For directory exclusions in tool-specific fields (e.g., linter.includes), using `!/path/to/dir/` is recommended to ensure the directory is properly excluded [8]. 4. Troubleshooting: If rules appear to be ignored: - Verify that your glob patterns are matching the intended files using documentation references [2]. - Check if the files are being unintentionally excluded by a broader `files.includes` pattern [6]. - Ensure you are not running into known issues regarding CLI execution paths or monorepo configurations, which can cause paths to be interpreted differently than expected [3][5]. For the most accurate debugging, ensure your `biome.json` is at the project root or correctly relative to your command execution, and verify the pattern syntax adheres to the current version's requirements [2][3][7].

Citations:


Include the maintainer configuration files in Biome’s coverage.

biome check . is the repo’s JS lint entry point, but files.includes only covers resources/**, tests/**, and playwright.config.ts. This leaves root package.json/biome.json and TS config files out of Biome’s lint/filter scope; add the intended config paths explicitly or document them as intentionally unlinted.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@biome.json` around lines 4 - 5, Update the Biome files.includes configuration
to explicitly include the repository’s maintainer configuration files, including
the root package.json, biome.json, and TypeScript configuration files, so biome
check . covers them. Preserve the existing resources, tests, and Playwright
entries, and use the intended explicit config paths rather than leaving them
unintentionally excluded.

"linter": {
"enabled": true,
"rules": {
"recommended": true,
"preset": "recommended",
"complexity": {
"noForEach": "off",
"noImportantStyles": "off",
"useOptionalChain": "off"
},
"correctness": {
"noUnusedVariables": "warn"
},
"style": {
"noDescendingSpecificity": "off",
"useTemplate": "off"
}
}
Expand Down
59 changes: 58 additions & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 10 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
"build:css": "bun build resources/css/admin.css --outdir assets --minify",
"build:static": "cp resources/ts/tinymce-separator.js assets/ && cp resources/css/tinymce-content.css assets/ && cp node_modules/tom-select/dist/css/tom-select.default.min.css assets/ && cp node_modules/tom-select/dist/js/tom-select.complete.min.js assets/",
"dev": "bun run build:js -- --watch & bun run build:css -- --watch",
"check": "bun run lint:php && bun run lint:js",
"lint": "biome check resources/",
"check": "bun run lint:php && bun run check:frontend",
"check:frontend": "bun run lint:js && bun run typecheck && bun run test:js",
"lint": "bun run lint:js",
"lint:php": "vendor/bin/phpcs",
"lint:js": "biome check resources/",
"lint:fix": "vendor/bin/phpcbf; bunx biome check --write resources/",
"lint:js": "biome check .",
"lint:fix": "(vendor/bin/phpcbf; [ $? -le 1 ]) && biome check --write .",
"typecheck": "tsc",
"analyse": "vendor/bin/phpstan analyse --memory-limit=1G",
"test": "vendor/bin/phpunit",
"test:js": "bun test tests/js",
Expand All @@ -29,7 +31,10 @@
"devDependencies": {
"@biomejs/biome": "^2.5.5",
"@playwright/test": "^1.62.0",
"@types/bun": "1.3.14",
"@types/node": "26.1.2",
"@types/sortablejs": "^1.15.9",
"@wordpress/env": "^11.11.0"
"@wordpress/env": "^11.11.0",
"typescript": "7.0.2"
}
}
14 changes: 7 additions & 7 deletions resources/css/admin.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@import './partials/base.css';
@import './partials/settings.css';
@import './partials/blocks.css';
@import './partials/post-meta.css';
@import './partials/preview.css';
@import './partials/ticker.css';
@import './partials/audit.css';
@import "./partials/base.css";
@import "./partials/settings.css";
@import "./partials/blocks.css";
@import "./partials/post-meta.css";
@import "./partials/preview.css";
@import "./partials/ticker.css";
@import "./partials/audit.css";
4 changes: 3 additions & 1 deletion resources/css/tinymce-content.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
body {
margin: 0 !important;
padding: 6px 8px !important;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue",
sans-serif;
font-size: 14px;
line-height: 1.6;
}
Expand Down
2 changes: 1 addition & 1 deletion resources/ts/modules/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function splitPages(html: string, enabled = true): string[] {

/** Debounce `fn`: each call restarts the timer; only the last call within `ms` runs. */
export function debounce(fn: () => void, ms: number): () => void {
let timer: ReturnType<typeof setTimeout> | undefined;
let timer: number | undefined;
return () => {
clearTimeout(timer);
timer = window.setTimeout(fn, ms);
Expand Down
2 changes: 1 addition & 1 deletion resources/ts/tinymce-separator.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// biome-ignore: TinyMCE 4 calls plugin callbacks with `new`, so these MUST be regular functions (not arrow functions).
// biome-ignore-all lint/complexity/useArrowFunction: Preserve TinyMCE 4-compatible legacy function syntax.
(function () {
if (typeof tinymce === 'undefined') return;

Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/global-setup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { mkdirSync } from 'node:fs';
import { dirname } from 'node:path';
import { type FullConfig, chromium } from '@playwright/test';
import { chromium, type FullConfig } from '@playwright/test';
import { ADMIN_STORAGE_STATE, login } from './helpers';
import { reseedFixtures } from './reseed-fixtures';

Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type Locator, type Page, expect } from '@playwright/test';
import { expect, type Locator, type Page } from '@playwright/test';

/** Admin session saved by global-setup and loaded by every test (see playwright.config.ts). */
export const ADMIN_STORAGE_STATE = '.playwright/auth/admin.json';
Expand Down
22 changes: 12 additions & 10 deletions tests/e2e/interactions.spec.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { type Locator, type Page, expect, test } from '@playwright/test';
import { expect, type Locator, type Page, test } from '@playwright/test';
import { addLoopBlock, addTickerBlock, submitAndReload } from './helpers';
import { reseedFixtures } from './reseed-fixtures';

const LOOP_URL = '/wp-admin/admin.php?page=teksttv-loop-tv1';

async function expectSequentialNames(root: Locator, itemSelector: string, prefix: string): Promise<void> {
// One evaluate round-trip: every item's field names, in DOM order.
const itemNames = await root.locator(itemSelector).evaluateAll((items) =>
items.map((item) =>
Array.from(item.querySelectorAll('input[name], select[name], textarea[name], [data-name]')).map(
(field) => field.getAttribute('name') ?? field.getAttribute('data-name'),
const itemNames = await root
.locator(itemSelector)
.evaluateAll((items) =>
items.map((item) =>
Array.from(item.querySelectorAll('input[name], select[name], textarea[name], [data-name]')).map(
(field) => field.getAttribute('name') ?? field.getAttribute('data-name'),
),
),
),
);
);

expect(itemNames.length, `${prefix} should contain at least one item`).toBeGreaterThan(0);
itemNames.forEach((names, index) => {
Expand Down Expand Up @@ -80,9 +82,9 @@ test.describe('admin interaction contracts', () => {
.evaluate((button) => {
button.dispatchEvent(new MouseEvent('click', { bubbles: true }));
const block = button.closest('.teksttv-block');
const controls = block?.querySelectorAll<
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
>('input, select, textarea');
const controls = block?.querySelectorAll<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(
'input, select, textarea',
);
return Array.from(controls ?? [], (control) => control.disabled);
});
expect(disabledStates.length).toBeGreaterThan(0);
Expand Down
Loading
Loading