oxlint-plugin-ts-no-assert 0.1.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.
Files changed (3) hide show
  1. package/README.md +77 -0
  2. package/dist/index.js +180 -0
  3. package/package.json +32 -0
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # oxlint-plugin-ts-no-assert
2
+
3
+ Disallow TypeScript type assertions (`as`, angle-bracket `<Type>`, and non-null `!`) — ported from [eslint-plugin-no-type-assertion](https://github.com/Dremora/eslint-plugin-no-type-assertion) to [Oxlint's JS plugin API](https://oxc.rs/docs/guide/usage/linter/plugins). Also works with ESLint flat config via the bundled `eslintCompatPlugin` wrapper.
4
+
5
+ ## Requirements
6
+
7
+ - Oxlint `>= 1.0.0` (requires `jsPlugins` support)
8
+ - Node.js `>= 18`
9
+
10
+ ## Installation
11
+
12
+ ```sh
13
+ npm add -D oxlint-plugin-ts-no-assert
14
+ # or
15
+ bun add -d oxlint-plugin-ts-no-assert
16
+ ```
17
+
18
+ ## Usage with Oxlint
19
+
20
+ Add the plugin to `jsPlugins` and enable the rule:
21
+
22
+ ```json
23
+ // .oxlintrc.json
24
+ {
25
+ "jsPlugins": ["./node_modules/oxlint-plugin-ts-no-assert/dist/index.js"],
26
+ "rules": {
27
+ "oxlint-plugin-ts-no-assert/no-type-assertion": "error"
28
+ }
29
+ }
30
+ ```
31
+
32
+ ## Usage with ESLint
33
+
34
+ ```js
35
+ // eslint.config.mjs
36
+ import tsNoAssertPlugin from "oxlint-plugin-ts-no-assert/dist/index.js";
37
+
38
+ export default [
39
+ {
40
+ plugins: { "no-type-assertion": tsNoAssertPlugin },
41
+ rules: tsNoAssertPlugin.configs.recommended.rules,
42
+ },
43
+ ];
44
+ ```
45
+
46
+ ## Rules
47
+
48
+ ### `no-type-assertion/no-type-assertion`
49
+
50
+ Disallows all three forms of TypeScript type assertion.
51
+
52
+ **Forbidden:**
53
+
54
+ ```ts
55
+ const x = value as MyType; // ❌ Do not use `as` operator for type assertion
56
+ const x = <MyType>value; // ❌ Do not use type assertion (angle-bracket)
57
+ const x = maybeNull!; // ❌ Do not use non-null assertion operator
58
+ ```
59
+
60
+ **Allowed** — safe widening that TypeScript itself endorses:
61
+
62
+ ```ts
63
+ const x = value as unknown; // ✅ widening to unknown is safe
64
+ const x = value as const; // ✅ const assertion
65
+ const x = <unknown>value; // ✅
66
+ const x = <const>value; // ✅
67
+ ```
68
+
69
+ > **Note on angle-bracket syntax:** TypeScript disallows `<Type>value` in `.tsx` files because it is syntactically ambiguous with JSX. The `angleBracketAssertion` diagnostic will only appear in plain `.ts` files.
70
+
71
+ | Rule | Description | Recommended |
72
+ |---|---|---|
73
+ | `no-type-assertion` | Disallow `as`, `<Type>`, and `!` type assertions (except `as const` / `as unknown`) | error |
74
+
75
+ ## License
76
+
77
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1,180 @@
1
+ // node_modules/.bun/@oxlint+plugins@1.43.0/node_modules/@oxlint/plugins/index.js
2
+ var EMPTY_VISITOR = {};
3
+ function eslintCompatPlugin(plugin) {
4
+ if (typeof plugin != "object" || !plugin)
5
+ throw Error("Plugin must be an object");
6
+ let { rules } = plugin;
7
+ if (typeof rules != "object" || !rules)
8
+ throw Error("Plugin must have an object as `rules` property");
9
+ for (let ruleName in rules)
10
+ Object.hasOwn(rules, ruleName) && convertRule(rules[ruleName]);
11
+ return plugin;
12
+ }
13
+ function convertRule(rule) {
14
+ if (typeof rule != "object" || !rule)
15
+ throw Error("Rule must be an object");
16
+ if ("create" in rule)
17
+ return;
18
+ let context = null, visitor, beforeHook;
19
+ rule.create = (eslintContext) => (context === null && ({ context, visitor, beforeHook } = createContextAndVisitor(rule)), Object.defineProperties(context, {
20
+ id: { value: eslintContext.id },
21
+ options: { value: eslintContext.options },
22
+ report: { value: eslintContext.report }
23
+ }), Object.setPrototypeOf(context, Object.getPrototypeOf(eslintContext)), beforeHook !== null && beforeHook() === false ? EMPTY_VISITOR : visitor);
24
+ }
25
+ var FILE_CONTEXT = Object.freeze({
26
+ get filename() {
27
+ throw Error("Cannot access `context.filename` in `createOnce`");
28
+ },
29
+ getFilename() {
30
+ throw Error("Cannot call `context.getFilename` in `createOnce`");
31
+ },
32
+ get physicalFilename() {
33
+ throw Error("Cannot access `context.physicalFilename` in `createOnce`");
34
+ },
35
+ getPhysicalFilename() {
36
+ throw Error("Cannot call `context.getPhysicalFilename` in `createOnce`");
37
+ },
38
+ get cwd() {
39
+ throw Error("Cannot access `context.cwd` in `createOnce`");
40
+ },
41
+ getCwd() {
42
+ throw Error("Cannot call `context.getCwd` in `createOnce`");
43
+ },
44
+ get sourceCode() {
45
+ throw Error("Cannot access `context.sourceCode` in `createOnce`");
46
+ },
47
+ getSourceCode() {
48
+ throw Error("Cannot call `context.getSourceCode` in `createOnce`");
49
+ },
50
+ get languageOptions() {
51
+ throw Error("Cannot access `context.languageOptions` in `createOnce`");
52
+ },
53
+ get settings() {
54
+ throw Error("Cannot access `context.settings` in `createOnce`");
55
+ },
56
+ extend(extension) {
57
+ return Object.freeze(Object.assign(Object.create(this), extension));
58
+ },
59
+ get parserOptions() {
60
+ throw Error("Cannot access `context.parserOptions` in `createOnce`");
61
+ },
62
+ get parserPath() {
63
+ throw Error("Cannot access `context.parserPath` in `createOnce`");
64
+ }
65
+ });
66
+ function createContextAndVisitor(rule) {
67
+ let { createOnce } = rule;
68
+ if (createOnce == null)
69
+ throw Error("Rules must define either a `create` or `createOnce` method");
70
+ if (typeof createOnce != "function")
71
+ throw Error("Rule `createOnce` property must be a function");
72
+ let context = Object.create(FILE_CONTEXT, {
73
+ id: {
74
+ value: "",
75
+ enumerable: true,
76
+ configurable: true
77
+ },
78
+ options: {
79
+ value: null,
80
+ enumerable: true,
81
+ configurable: true
82
+ },
83
+ report: {
84
+ value: null,
85
+ enumerable: true,
86
+ configurable: true
87
+ }
88
+ }), { before: beforeHook, after: afterHook, ...visitor } = createOnce.call(rule, context);
89
+ if (beforeHook === undefined)
90
+ beforeHook = null;
91
+ else if (beforeHook !== null && typeof beforeHook != "function")
92
+ throw Error("`before` property of visitor must be a function if defined");
93
+ if (afterHook != null) {
94
+ if (typeof afterHook != "function")
95
+ throw Error("`after` property of visitor must be a function if defined");
96
+ let maxAttrs = -1;
97
+ for (let key2 in visitor) {
98
+ if (!Object.hasOwn(visitor, key2) || !key2.endsWith(":exit"))
99
+ continue;
100
+ let end = key2.length - 5, count = 0;
101
+ for (let i = 0;i < end; i++) {
102
+ let c = key2.charCodeAt(i);
103
+ (c === 91 || c === 46 || c === 58) && count++;
104
+ }
105
+ count > maxAttrs && (maxAttrs = count);
106
+ }
107
+ let key = `Program${"[type]".repeat(maxAttrs + 1)}:exit`;
108
+ visitor[key] = (_node) => afterHook();
109
+ }
110
+ return {
111
+ context,
112
+ visitor,
113
+ beforeHook
114
+ };
115
+ }
116
+
117
+ // packages/plugin-no-type-assertion/src/rules/no-type-assertion.ts
118
+ function isAllowedTypeAnnotation(typeAnnotation) {
119
+ if (typeAnnotation.type === "TSUnknownKeyword") {
120
+ return true;
121
+ }
122
+ if (typeAnnotation.type === "TSTypeReference" && typeAnnotation.typeName?.type === "Identifier" && typeAnnotation.typeName?.name === "const") {
123
+ return true;
124
+ }
125
+ return false;
126
+ }
127
+ var no_type_assertion_default = {
128
+ meta: {
129
+ type: "suggestion",
130
+ docs: {
131
+ description: "Disallow type assertions in TypeScript code.",
132
+ recommended: "error"
133
+ },
134
+ messages: {
135
+ angleBracketAssertion: "Do not use type assertion",
136
+ asAssertion: "Do not use `as` operator for type assertion",
137
+ nonNullAssertion: "Do not use non-null assertion operator"
138
+ },
139
+ schema: []
140
+ },
141
+ defaultOptions: [],
142
+ createOnce(context) {
143
+ return {
144
+ TSTypeAssertion(node) {
145
+ if (isAllowedTypeAnnotation(node.typeAnnotation)) {
146
+ return;
147
+ }
148
+ context.report({ node, messageId: "angleBracketAssertion" });
149
+ },
150
+ TSAsExpression(node) {
151
+ if (isAllowedTypeAnnotation(node.typeAnnotation)) {
152
+ return;
153
+ }
154
+ context.report({ node, messageId: "asAssertion" });
155
+ },
156
+ TSNonNullExpression(node) {
157
+ context.report({ node, messageId: "nonNullAssertion" });
158
+ }
159
+ };
160
+ }
161
+ };
162
+
163
+ // packages/plugin-no-type-assertion/src/index.ts
164
+ var plugin = eslintCompatPlugin({
165
+ meta: { name: "oxlint-plugin-ts-no-assert" },
166
+ rules: {
167
+ "no-type-assertion": no_type_assertion_default
168
+ },
169
+ configs: {
170
+ recommended: {
171
+ rules: {
172
+ "no-type-assertion/no-type-assertion": "error"
173
+ }
174
+ }
175
+ }
176
+ });
177
+ var src_default = plugin;
178
+ export {
179
+ src_default as default
180
+ };
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "oxlint-plugin-ts-no-assert",
3
+ "version": "0.1.1",
4
+ "type": "module",
5
+ "description": "Disallow TypeScript type assertions (as, angle-bracket, non-null !) — ported from eslint-plugin-no-type-assertion to Oxlint's JS plugin API. Also compatible with ESLint flat config.",
6
+ "license": "MIT",
7
+ "main": "./dist/index.js",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "README.md"
16
+ ],
17
+ "keywords": [
18
+ "oxlint",
19
+ "eslint",
20
+ "typescript",
21
+ "type-assertion",
22
+ "non-null-assertion",
23
+ "lint"
24
+ ],
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/takinprofit/biome-plugins"
28
+ },
29
+ "engines": {
30
+ "node": ">=18.0.0"
31
+ }
32
+ }