Skip to content

Commit 99eaebc

Browse files
chore: linting and agents file. (#55)
1 parent 0726c2a commit 99eaebc

9 files changed

Lines changed: 232 additions & 64 deletions

File tree

.oxlintrc.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
{
22
"$schema": "https://json.schemastore.org/oxlintrc",
3-
"plugins": ["typescript", "unicorn", "oxc", "react", "node", "import", "vitest"],
3+
"plugins": [
4+
"eslint",
5+
"typescript",
6+
"unicorn",
7+
"oxc",
8+
"react",
9+
"node",
10+
"import",
11+
"vitest"
12+
],
413
"env": {
514
"es2022": true,
615
"node": true
@@ -9,6 +18,9 @@
918
"process": "readonly"
1019
},
1120
"rules": {
21+
"no-shadow": "off",
22+
"@typescript-eslint/no-shadow": "error",
23+
"@typescript-eslint/no-explicit-any": "error",
1224
"unicorn/filename-case": [
1325
"error",
1426
{

AGENTS.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
---
2+
name: knighted-css-agent
3+
description: Specialist coding agent for @knighted/css (TypeScript, Node, Lightning CSS).
4+
---
5+
6+
You are a specialist engineer for the @knighted/css monorepo. Focus on the core package and its tests, keep changes minimal, and validate with the listed commands.
7+
8+
## Commands (run early and often)
9+
10+
Repo root commands:
11+
12+
- Install: `npm install`
13+
- Build: `npm run build`
14+
- Lint: `npm run lint`
15+
- Format check: `npm run prettier:check`
16+
- Format write: `npm run prettier`
17+
- Typecheck: `npm run check-types`
18+
- Unit tests: `npm run test`
19+
- E2E tests: `npm run test:e2e`
20+
21+
Workspace-scoped (preferred when changing @knighted/css only):
22+
23+
- Build: `npm run build -w @knighted/css`
24+
- Typecheck: `npm run check-types -w @knighted/css`
25+
- Tests: `npm run test -w @knighted/css`
26+
27+
## Project knowledge
28+
29+
**Tech stack**
30+
31+
- Node.js >= 22.21.1, npm >= 10.9.0
32+
- TypeScript 5.9 (strict, ESM, NodeNext resolution)
33+
- lightningcss for CSS transforms
34+
- oxc-resolver and get-tsconfig for module resolution
35+
- tsx + c8 for unit tests
36+
- Playwright for end-to-end coverage
37+
38+
**Repository structure**
39+
40+
- packages/css/src — core library (graph walking, compilation, loader helpers)
41+
- packages/css/test — unit tests
42+
- packages/css/docs — package docs and deep dives
43+
- packages/playwright — E2E demo + regression suite
44+
- docs — root-level documentation
45+
46+
## Code style and conventions
47+
48+
- TypeScript strict is enabled; prefer precise types and `unknown` over `any`.
49+
- Avoid TypeScript assertions by providing type predicates.
50+
- Rely on TypeScript inference over explicit typing as much as possible.
51+
- ESM only (`type: module`).
52+
- Prettier: single quotes, no semicolons, `printWidth: 90`, `arrowParens: avoid`.
53+
- Keep functions small and side-effect aware; prefer pure helpers where possible.
54+
55+
### Example style (good)
56+
57+
```ts
58+
type SelectorNode = { type: string; value?: string }
59+
60+
function toClassSelectors(nodes: SelectorNode[]): SelectorNode[] {
61+
return nodes.filter(node => node.type === 'class')
62+
}
63+
```
64+
65+
### Example style (avoid)
66+
67+
```ts
68+
// vague types, implicit any, and unclear intent
69+
function f(x) {
70+
return x
71+
}
72+
```
73+
74+
## Testing expectations
75+
76+
- Update or add tests under packages/css/test when modifying behavior.
77+
- For loader/runtime changes, consider adding or updating Playwright coverage under packages/playwright.
78+
- Run typecheck after TypeScript edits.
79+
80+
## Git workflow
81+
82+
- Keep changes focused to the smallest surface area.
83+
- Update tests alongside logic changes.
84+
- Don’t reformat unrelated files.
85+
86+
## Boundaries
87+
88+
**Always:**
89+
90+
- Follow the commands above to validate changes.
91+
- Maintain ESM + strict TypeScript compatibility.
92+
- Keep changes localized to the affected workspace.
93+
94+
**Ask first:**
95+
96+
- Adding or upgrading dependencies.
97+
- Modifying CI workflows, build scripts, or publishing configuration.
98+
- Changing public API surface or documented behavior.
99+
100+
**Never:**
101+
102+
- Commit secrets or credentials.
103+
- Edit generated artifacts (packages/css/dist, packages/css/stable, packages/css/types-stub, coverage, test-results).
104+
- Modify node_modules or lockfiles unless explicitly requested.

package-lock.json

Lines changed: 36 additions & 37 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"less": "^4.2.0",
4848
"lint-staged": "^16.2.7",
4949
"madge": "^8.0.0",
50-
"oxlint": "^1.35.0",
50+
"oxlint": "^1.39.0",
5151
"prettier": "^3.7.4",
5252
"sass": "^1.80.7",
5353
"tsx": "^4.19.2",

packages/css/src/helpers.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import { type TransformOptions as LightningTransformOptions } from 'lightningcss'
22

3+
import type {
4+
LightningStyleRule,
5+
LightningStyleRuleReturn,
6+
LightningVisitor,
7+
} from './types.js'
8+
39
export type SpecificitySelector = string | RegExp
410

5-
export type LightningVisitor = LightningTransformOptions<Record<string, never>>['visitor']
11+
export type { LightningVisitor }
612

713
export type SpecificityStrategy =
814
| { type: 'append-where'; token: string }
@@ -27,10 +33,16 @@ export function buildSpecificityVisitor(boost?: {
2733
const times = Math.max(1, boost.strategy.times ?? 1)
2834
const visitor: LightningVisitor = {
2935
Rule: {
30-
style(rule: any) {
31-
if (!rule || !Array.isArray(rule.selectors)) return rule
32-
const newSelectors = rule.selectors.map((sel: any) => {
33-
const selectorStr = serializeSelector(sel)
36+
style(rule: LightningStyleRule): LightningStyleRuleReturn {
37+
const candidate = rule as { selectors?: unknown } | null | undefined
38+
if (!candidate || !Array.isArray(candidate.selectors)) {
39+
return rule as LightningStyleRuleReturn
40+
}
41+
const newSelectors = candidate.selectors.map((sel: unknown) => {
42+
if (!Array.isArray(sel)) return sel
43+
const selectorStr = serializeSelector(
44+
sel as Parameters<typeof serializeSelector>[0],
45+
)
3446
if (!shouldApply(selectorStr)) return sel
3547
const lastClassName = findLastClassName(selectorStr)
3648
if (!lastClassName) return sel
@@ -40,7 +52,10 @@ export function buildSpecificityVisitor(boost?: {
4052
}))
4153
return [...sel, ...repeats]
4254
})
43-
return { ...rule, selectors: newSelectors }
55+
return {
56+
...candidate,
57+
selectors: newSelectors,
58+
} as unknown as LightningStyleRuleReturn
4459
},
4560
},
4661
}
@@ -51,10 +66,16 @@ export function buildSpecificityVisitor(boost?: {
5166
const token = boost.strategy.token
5267
const visitor: LightningTransformOptions<never>['visitor'] = {
5368
Rule: {
54-
style(rule: any) {
55-
if (!rule || !Array.isArray(rule.selectors)) return rule
56-
const newSelectors = rule.selectors.map((sel: any) => {
57-
const selectorStr = serializeSelector(sel)
69+
style(rule: LightningStyleRule): LightningStyleRuleReturn {
70+
const candidate = rule as { selectors?: unknown } | null | undefined
71+
if (!candidate || !Array.isArray(candidate.selectors)) {
72+
return rule as LightningStyleRuleReturn
73+
}
74+
const newSelectors = candidate.selectors.map((sel: unknown) => {
75+
if (!Array.isArray(sel)) return sel
76+
const selectorStr = serializeSelector(
77+
sel as Parameters<typeof serializeSelector>[0],
78+
)
5879
if (!shouldApply(selectorStr)) return sel
5980
return [
6081
...sel,
@@ -65,7 +86,10 @@ export function buildSpecificityVisitor(boost?: {
6586
},
6687
]
6788
})
68-
return { ...rule, selectors: newSelectors }
89+
return {
90+
...candidate,
91+
selectors: newSelectors,
92+
} as unknown as LightningStyleRuleReturn
6993
},
7094
},
7195
}

packages/css/src/moduleGraph.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ function loadTsconfigPaths(
625625
if (cached !== undefined) {
626626
return cached ?? undefined
627627
}
628-
const result = getTsconfig(target, undefined, tsconfigFsCache as Map<string, any>)
628+
const result = getTsconfig(target, undefined, tsconfigFsCache as Map<string, unknown>)
629629
if (!result) {
630630
tsconfigResultCache.set(target, null)
631631
return undefined

0 commit comments

Comments
 (0)