@timmo001/oxlint-rules 0.1.4 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -5
- package/dist/cli.js +184 -77
- package/dist/configs/effect.js +144 -72
- package/dist/configs/recommended.js +74 -2
- package/dist/generic/index.js +70 -0
- package/package.json +5 -2
- package/skills/add-oxlint-rule/SKILL.md +6 -2
- package/skills/install-timmo-oxlint-rules/SKILL.md +8 -8
- package/skills/release-oxlint-rules/SKILL.md +38 -0
- package/src/generic/index.ts +12 -0
- package/src/generic/rules/prefer-event-parameter-type.ts +83 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release-oxlint-rules
|
|
3
|
+
description: >-
|
|
4
|
+
Create and publish a major, minor, or patch release of
|
|
5
|
+
@timmo001/oxlint-rules. Use when asked to create, cut, prepare, or publish an
|
|
6
|
+
oxlint-rules release, including its version bump and npm and JSR publication.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Release Oxlint Rules
|
|
10
|
+
|
|
11
|
+
1. Find a writable checkout whose Git remote is
|
|
12
|
+
`timmo001/oxlint-rules`. Read its `AGENTS.md`, package metadata, release
|
|
13
|
+
workflow, latest tags, and changes since the latest release. Stop if the
|
|
14
|
+
worktree contains unrelated changes or the local branch is behind its
|
|
15
|
+
remote.
|
|
16
|
+
2. Confirm `package.json` and `jsr.json` have the same current version and that
|
|
17
|
+
its release exists. Resolve the next version from the requested major,
|
|
18
|
+
minor, patch, or exact version. Ask only when the release level is missing.
|
|
19
|
+
Do not add a `v` prefix when the repository's existing tags omit it.
|
|
20
|
+
3. Update the version in `package.json` and `jsr.json`. Before committing, run
|
|
21
|
+
`mise run check`, `mise run build`, `npm pack --dry-run`, and
|
|
22
|
+
`bunx jsr@0.14.3 publish --dry-run --allow-dirty`. The dirty-tree flag is
|
|
23
|
+
required because the intended version bump is not committed yet.
|
|
24
|
+
4. Treat a direct request to create or publish the release as authorisation for
|
|
25
|
+
its version commit, push, and GitHub release. Follow the active environment's
|
|
26
|
+
guarded commit and push workflow, committing only the release metadata with
|
|
27
|
+
`Release Oxlint rules <version>`. A request to prepare or plan a release does
|
|
28
|
+
not authorise publication.
|
|
29
|
+
5. Resolve the target only after the push with `git rev-parse HEAD`. Pass the
|
|
30
|
+
resulting full 40-character SHA as the `--target` value when running
|
|
31
|
+
`gh release create`. Never pass an abbreviated SHA as `target_commitish`.
|
|
32
|
+
6. Create the release before resolving workflow targets because publication is
|
|
33
|
+
triggered by the `release.published` event. Watch only the release commit's
|
|
34
|
+
exact workflow runs and require both `Publish to npm` and `Publish to JSR` to
|
|
35
|
+
succeed.
|
|
36
|
+
7. Report the release URL, version commit, validation results, and npm and JSR
|
|
37
|
+
publication conclusions. Do not report the release as complete while either
|
|
38
|
+
publication job is pending or failed.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { eslintCompatPlugin } from "@oxlint/plugins";
|
|
2
|
+
|
|
3
|
+
import { preferEventParameterTypeRule } from "./rules/prefer-event-parameter-type.ts";
|
|
4
|
+
|
|
5
|
+
const timmoPlugin = eslintCompatPlugin({
|
|
6
|
+
meta: { name: "timmo" },
|
|
7
|
+
rules: {
|
|
8
|
+
"prefer-event-parameter-type": preferEventParameterTypeRule,
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export default timmoPlugin;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { defineRule } from "@oxlint/plugins";
|
|
2
|
+
|
|
3
|
+
import type { ESTree } from "@oxlint/plugins";
|
|
4
|
+
|
|
5
|
+
type FunctionNode = ESTree.Function | ESTree.ArrowFunctionExpression;
|
|
6
|
+
type TypeAssertion = ESTree.TSAsExpression | ESTree.TSTypeAssertion;
|
|
7
|
+
|
|
8
|
+
function nearestEnclosingFunction(node: ESTree.Node): FunctionNode | null {
|
|
9
|
+
let current: ESTree.Node | null = node.parent;
|
|
10
|
+
while (current) {
|
|
11
|
+
if (
|
|
12
|
+
current.type === "FunctionDeclaration" ||
|
|
13
|
+
current.type === "FunctionExpression" ||
|
|
14
|
+
current.type === "ArrowFunctionExpression"
|
|
15
|
+
) {
|
|
16
|
+
return current;
|
|
17
|
+
}
|
|
18
|
+
current = current.parent;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function assertedEventParameter(node: TypeAssertion): {
|
|
24
|
+
readonly parameter: string;
|
|
25
|
+
readonly property: "currentTarget" | "target";
|
|
26
|
+
} | null {
|
|
27
|
+
const expression = node.expression;
|
|
28
|
+
if (
|
|
29
|
+
expression.type !== "MemberExpression" ||
|
|
30
|
+
expression.computed ||
|
|
31
|
+
expression.object.type !== "Identifier" ||
|
|
32
|
+
expression.property.type !== "Identifier" ||
|
|
33
|
+
(expression.property.name !== "currentTarget" &&
|
|
34
|
+
expression.property.name !== "target")
|
|
35
|
+
) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const parameterName = expression.object.name;
|
|
39
|
+
const property = expression.property.name;
|
|
40
|
+
const owner = nearestEnclosingFunction(node);
|
|
41
|
+
if (
|
|
42
|
+
!owner?.params.some(
|
|
43
|
+
(parameter) =>
|
|
44
|
+
parameter.type === "Identifier" && parameter.name === parameterName,
|
|
45
|
+
)
|
|
46
|
+
) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
parameter: parameterName,
|
|
51
|
+
property,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Prefer expressing an event target type in its handler parameter signature. */
|
|
56
|
+
export const preferEventParameterTypeRule = defineRule({
|
|
57
|
+
meta: {
|
|
58
|
+
type: "suggestion",
|
|
59
|
+
docs: {
|
|
60
|
+
description:
|
|
61
|
+
"Prefer typing event target properties in the handler parameter instead of asserting them at use sites.",
|
|
62
|
+
},
|
|
63
|
+
messages: {
|
|
64
|
+
typeEventParameter:
|
|
65
|
+
"Type `{{parameter}}.{{property}}` in the function signature instead of asserting it at the use site.",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
create(context) {
|
|
69
|
+
const checkAssertion = (node: TypeAssertion) => {
|
|
70
|
+
const eventParameter = assertedEventParameter(node);
|
|
71
|
+
if (!eventParameter) return;
|
|
72
|
+
context.report({
|
|
73
|
+
node,
|
|
74
|
+
messageId: "typeEventParameter",
|
|
75
|
+
data: eventParameter,
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
return {
|
|
79
|
+
TSAsExpression: checkAssertion,
|
|
80
|
+
TSTypeAssertion: checkAssertion,
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
});
|