@pobammer-ts/small-rules 1.0.0 → 1.1.0
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 +35 -0
- package/dist/index.js +81 -82
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# `@pobammer-ts/small-rules`
|
|
2
|
+
|
|
3
|
+
A collection of [Oxlint](https://oxc.rs)-native rules for linting [roblox-ts](https://roblox-ts.com/) projects.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
ni -D @pobammer-ts/small-rules
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This package is an [Oxlint plugin](https://oxc.rs/docs/guide/usage/plugins) and must be used with [Oxlint](https://oxc.rs) v1.69.0 or later. It also requires TypeScript 6 and Node.js `^20.19.0` / `>=22.12.0`.
|
|
12
|
+
|
|
13
|
+
## Configuration
|
|
14
|
+
|
|
15
|
+
Register the plugin in your `.oxlintrc.json` and enable the rules you want:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"plugins": ["@pobammer-ts/small-rules"],
|
|
20
|
+
"rules": {
|
|
21
|
+
"small-rules/no-print": "error",
|
|
22
|
+
"small-rules/no-warn": "error"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
All rules are namespaced under the `small-rules/` prefix. Pick the subset that fits your project — there is no bulk opt-in.
|
|
28
|
+
|
|
29
|
+
## Rules
|
|
30
|
+
|
|
31
|
+
Full rule documentation is forthcoming alongside the project docs site.
|
|
32
|
+
|
|
33
|
+
## License
|
|
34
|
+
|
|
35
|
+
MIT © HowManySmall
|
package/dist/index.js
CHANGED
|
@@ -1230,92 +1230,25 @@ function addScore(current, addition, config, ceiling) {
|
|
|
1230
1230
|
if (!config.performanceMode) return nextScore;
|
|
1231
1231
|
return Math.min(nextScore, ceiling);
|
|
1232
1232
|
}
|
|
1233
|
+
function addStructuralScore(current, node, depth, config, cache, depthMultiplierCache, ceiling, bonus = 0) {
|
|
1234
|
+
return addScore(current, calculateStructuralComplexity(node, depth, config, cache, depthMultiplierCache, ceiling) + bonus, config, ceiling);
|
|
1235
|
+
}
|
|
1233
1236
|
function addNestedTypeAnnotationScores(current, members, depth, config, cache, depthMultiplierCache, ceiling) {
|
|
1234
1237
|
let score = current;
|
|
1235
1238
|
for (const member of members) {
|
|
1236
1239
|
const typeAnnotation = getNestedTypeAnnotation(member);
|
|
1237
1240
|
if (typeAnnotation === void 0) continue;
|
|
1238
|
-
score =
|
|
1241
|
+
score = addStructuralScore(score, typeAnnotation, depth, config, cache, depthMultiplierCache, ceiling);
|
|
1239
1242
|
}
|
|
1240
1243
|
return score;
|
|
1241
1244
|
}
|
|
1242
1245
|
function getDepthMultiplier(depth, cache) {
|
|
1243
1246
|
const cached = cache.get(depth);
|
|
1244
1247
|
if (cached !== void 0) return cached;
|
|
1245
|
-
const computed = Math.
|
|
1248
|
+
const computed = Math.log2(depth + 1);
|
|
1246
1249
|
cache.set(depth, computed);
|
|
1247
1250
|
return computed;
|
|
1248
1251
|
}
|
|
1249
|
-
function calculateChildComplexity(node, depth, config, cache, depthMultiplierCache, ceiling) {
|
|
1250
|
-
return calculateStructuralComplexity(node, depth, config, cache, depthMultiplierCache, ceiling);
|
|
1251
|
-
}
|
|
1252
|
-
function addChildComplexity(score, node, depth, config, cache, depthMultiplierCache, ceiling) {
|
|
1253
|
-
return addScore(score, calculateChildComplexity(node, depth, config, cache, depthMultiplierCache, ceiling), config, ceiling);
|
|
1254
|
-
}
|
|
1255
|
-
function getDefinedNodes(nodes) {
|
|
1256
|
-
return nodes.filter((node) => node !== void 0);
|
|
1257
|
-
}
|
|
1258
|
-
function addChildComplexities(score, nodes, depth, config, cache, depthMultiplierCache, ceiling) {
|
|
1259
|
-
let nextScore = score;
|
|
1260
|
-
for (const child of nodes) nextScore = addChildComplexity(nextScore, child, depth, config, cache, depthMultiplierCache, ceiling);
|
|
1261
|
-
return nextScore;
|
|
1262
|
-
}
|
|
1263
|
-
function calculateArrayTypeComplexity(node, depth, config, cache, depthMultiplierCache, ceiling) {
|
|
1264
|
-
if (!isRecord$1(node)) return 1;
|
|
1265
|
-
const elementType = getNodeValue(node, "elementType");
|
|
1266
|
-
if (elementType === void 0) return 1;
|
|
1267
|
-
return addScore(calculateChildComplexity(elementType, depth, config, cache, depthMultiplierCache, ceiling), 1, config, ceiling);
|
|
1268
|
-
}
|
|
1269
|
-
function calculateConditionalTypeComplexity(node, depth, config, cache, depthMultiplierCache, ceiling) {
|
|
1270
|
-
if (!isRecord$1(node)) return 3;
|
|
1271
|
-
return addChildComplexities(3, getDefinedNodes([
|
|
1272
|
-
getNodeValue(node, "checkType"),
|
|
1273
|
-
getNodeValue(node, "extendsType"),
|
|
1274
|
-
getNodeValue(node, "trueType"),
|
|
1275
|
-
getNodeValue(node, "falseType")
|
|
1276
|
-
]), depth, config, cache, depthMultiplierCache, ceiling);
|
|
1277
|
-
}
|
|
1278
|
-
function calculateFunctionTypeComplexity(node, depth, config, cache, depthMultiplierCache, ceiling) {
|
|
1279
|
-
if (!isRecord$1(node)) return 2;
|
|
1280
|
-
return addChildComplexities(2, getDefinedNodes([...getNodeArrayValue(node, "params")?.map(getNestedTypeAnnotation) ?? [], getReturnTypeAnnotation$1(node)]), depth, config, cache, depthMultiplierCache, ceiling);
|
|
1281
|
-
}
|
|
1282
|
-
function calculateInterfaceComplexity(node, depth, config, cache, depthMultiplierCache, ceiling) {
|
|
1283
|
-
if (!isRecord$1(node)) return config.interfacePenalty;
|
|
1284
|
-
const extendsLength = getNodeArrayValue(node, "extends")?.length ?? 0;
|
|
1285
|
-
const body = getNodeValue(node, "body");
|
|
1286
|
-
const members = body !== void 0 && isRecord$1(body) ? getNodeArrayValue(body, "body") ?? [] : [];
|
|
1287
|
-
let score = config.interfacePenalty;
|
|
1288
|
-
if (extendsLength > 0) score = addScore(score, extendsLength * 5, config, ceiling);
|
|
1289
|
-
score = addScore(score, members.length * 2, config, ceiling);
|
|
1290
|
-
return addNestedTypeAnnotationScores(score, members, depth, config, cache, depthMultiplierCache, ceiling);
|
|
1291
|
-
}
|
|
1292
|
-
function calculateTypeListComplexity(node, depth, typePenalty, config, cache, depthMultiplierCache, ceiling) {
|
|
1293
|
-
if (!isRecord$1(node)) return 0;
|
|
1294
|
-
const types = getNodeArrayValue(node, "types") ?? [];
|
|
1295
|
-
return addScore(addChildComplexities(0, types, depth, config, cache, depthMultiplierCache, ceiling), typePenalty(types.length), config, ceiling);
|
|
1296
|
-
}
|
|
1297
|
-
function calculateMappedTypeComplexity(node, depth, config, cache, depthMultiplierCache, ceiling) {
|
|
1298
|
-
if (!isRecord$1(node)) return 5;
|
|
1299
|
-
return addChildComplexities(5, getDefinedNodes([getNodeValue(node, "constraint"), getNodeValue(node, "typeAnnotation")]), depth, config, cache, depthMultiplierCache, ceiling);
|
|
1300
|
-
}
|
|
1301
|
-
function calculateTupleTypeComplexity(node, depth, config, cache, depthMultiplierCache, ceiling) {
|
|
1302
|
-
if (!isRecord$1(node)) return 0;
|
|
1303
|
-
const elementTypes = getNodeArrayValue(node, "elementTypes") ?? [];
|
|
1304
|
-
return addScore(addChildComplexities(1, elementTypes.filter((element) => element.type !== "TSRestType" && element.type !== "TSOptionalType"), depth, config, cache, depthMultiplierCache, ceiling), 1.5 * elementTypes.length, config, ceiling);
|
|
1305
|
-
}
|
|
1306
|
-
function calculateTypeLiteralComplexity(node, depth, config, cache, depthMultiplierCache, ceiling) {
|
|
1307
|
-
if (!isRecord$1(node)) return 0;
|
|
1308
|
-
const members = getNodeArrayValue(node, "members") ?? [];
|
|
1309
|
-
return addNestedTypeAnnotationScores(2 + members.length * .5, members, depth, config, cache, depthMultiplierCache, ceiling);
|
|
1310
|
-
}
|
|
1311
|
-
function calculateTypeReferenceComplexity(node, depth, config, cache, depthMultiplierCache, ceiling) {
|
|
1312
|
-
if (!isRecord$1(node)) return 2;
|
|
1313
|
-
const typeArguments = getNodeValue(node, "typeArguments");
|
|
1314
|
-
const parameters = typeArguments !== void 0 && isRecord$1(typeArguments) ? getNodeArrayValue(typeArguments, "params") ?? [] : [];
|
|
1315
|
-
let score = 2;
|
|
1316
|
-
for (const parameter of parameters) score = addScore(score, calculateChildComplexity(parameter, depth, config, cache, depthMultiplierCache, ceiling) + 2, config, ceiling);
|
|
1317
|
-
return score;
|
|
1318
|
-
}
|
|
1319
1252
|
function calculateStructuralComplexity(node, depth, config, cache, depthMultiplierCache, ceiling) {
|
|
1320
1253
|
const cached = cache.nodeCache.get(node);
|
|
1321
1254
|
if (cached !== void 0) return cached;
|
|
@@ -1328,7 +1261,14 @@ function calculateStructuralComplexity(node, depth, config, cache, depthMultipli
|
|
|
1328
1261
|
case "TSNeverKeyword":
|
|
1329
1262
|
case "TSUnknownKeyword": break;
|
|
1330
1263
|
case "TSArrayType":
|
|
1331
|
-
|
|
1264
|
+
if (isRecord$1(node)) {
|
|
1265
|
+
const elementType = getNodeValue(node, "elementType");
|
|
1266
|
+
if (elementType !== void 0) {
|
|
1267
|
+
score = addScore(calculateStructuralComplexity(elementType, nextDepth, config, cache, depthMultiplierCache, ceiling), 1, config, ceiling);
|
|
1268
|
+
break;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
score = 1;
|
|
1332
1272
|
break;
|
|
1333
1273
|
case "TSBigIntKeyword":
|
|
1334
1274
|
case "TSBooleanKeyword":
|
|
@@ -1341,32 +1281,91 @@ function calculateStructuralComplexity(node, depth, config, cache, depthMultipli
|
|
|
1341
1281
|
score = 1;
|
|
1342
1282
|
break;
|
|
1343
1283
|
case "TSConditionalType":
|
|
1344
|
-
score =
|
|
1284
|
+
score = 3;
|
|
1285
|
+
if (isRecord$1(node)) {
|
|
1286
|
+
const checkType = getNodeValue(node, "checkType");
|
|
1287
|
+
const extendsType = getNodeValue(node, "extendsType");
|
|
1288
|
+
const trueType = getNodeValue(node, "trueType");
|
|
1289
|
+
const falseType = getNodeValue(node, "falseType");
|
|
1290
|
+
if (checkType !== void 0) score = addScore(score, calculateStructuralComplexity(checkType, nextDepth, config, cache, depthMultiplierCache, ceiling), config, ceiling);
|
|
1291
|
+
if (extendsType !== void 0) score = addScore(score, calculateStructuralComplexity(extendsType, nextDepth, config, cache, depthMultiplierCache, ceiling), config, ceiling);
|
|
1292
|
+
if (trueType !== void 0) score = addScore(score, calculateStructuralComplexity(trueType, nextDepth, config, cache, depthMultiplierCache, ceiling), config, ceiling);
|
|
1293
|
+
if (falseType !== void 0) score = addScore(score, calculateStructuralComplexity(falseType, nextDepth, config, cache, depthMultiplierCache, ceiling), config, ceiling);
|
|
1294
|
+
}
|
|
1345
1295
|
break;
|
|
1346
1296
|
case "TSFunctionType":
|
|
1347
1297
|
case "TSMethodSignature":
|
|
1348
|
-
score =
|
|
1298
|
+
score = 2;
|
|
1299
|
+
if (isRecord$1(node)) {
|
|
1300
|
+
const parameters = getNodeArrayValue(node, "params") ?? [];
|
|
1301
|
+
for (const parameter of parameters) {
|
|
1302
|
+
const typeAnnotation = getNestedTypeAnnotation(parameter);
|
|
1303
|
+
if (typeAnnotation === void 0) continue;
|
|
1304
|
+
score = addScore(score, calculateStructuralComplexity(typeAnnotation, nextDepth, config, cache, depthMultiplierCache, ceiling), config, ceiling);
|
|
1305
|
+
}
|
|
1306
|
+
const returnType = getReturnTypeAnnotation$1(node);
|
|
1307
|
+
if (returnType !== void 0) score = addScore(score, calculateStructuralComplexity(returnType, nextDepth, config, cache, depthMultiplierCache, ceiling), config, ceiling);
|
|
1308
|
+
}
|
|
1349
1309
|
break;
|
|
1350
1310
|
case "TSInterfaceDeclaration":
|
|
1351
|
-
score =
|
|
1311
|
+
score = config.interfacePenalty;
|
|
1312
|
+
if (isRecord$1(node)) {
|
|
1313
|
+
const extendsLength = getNodeArrayValue(node, "extends")?.length;
|
|
1314
|
+
if (extendsLength !== void 0 && extendsLength > 0) score = addScore(score, extendsLength * 5, config, ceiling);
|
|
1315
|
+
const body = getNodeValue(node, "body");
|
|
1316
|
+
const members = body !== void 0 && isRecord$1(body) ? getNodeArrayValue(body, "body") ?? [] : [];
|
|
1317
|
+
score = addScore(score, members.length * 2, config, ceiling);
|
|
1318
|
+
score = addNestedTypeAnnotationScores(score, members, nextDepth, config, cache, depthMultiplierCache, ceiling);
|
|
1319
|
+
}
|
|
1352
1320
|
break;
|
|
1353
1321
|
case "TSIntersectionType":
|
|
1354
|
-
|
|
1322
|
+
if (isRecord$1(node)) {
|
|
1323
|
+
const types = getNodeArrayValue(node, "types") ?? [];
|
|
1324
|
+
for (const type of types) score = addStructuralScore(score, type, nextDepth, config, cache, depthMultiplierCache, ceiling);
|
|
1325
|
+
score = addScore(score, 3 * types.length, config, ceiling);
|
|
1326
|
+
}
|
|
1355
1327
|
break;
|
|
1356
1328
|
case "TSMappedType":
|
|
1357
|
-
score =
|
|
1329
|
+
score = 5;
|
|
1330
|
+
if (isRecord$1(node)) {
|
|
1331
|
+
const constraint = getNodeValue(node, "constraint");
|
|
1332
|
+
if (constraint !== void 0) score = addStructuralScore(score, constraint, nextDepth, config, cache, depthMultiplierCache, ceiling);
|
|
1333
|
+
const typeAnnotation = getNodeValue(node, "typeAnnotation");
|
|
1334
|
+
if (typeAnnotation !== void 0) score = addStructuralScore(score, typeAnnotation, nextDepth, config, cache, depthMultiplierCache, ceiling);
|
|
1335
|
+
}
|
|
1358
1336
|
break;
|
|
1359
1337
|
case "TSTupleType":
|
|
1360
|
-
|
|
1338
|
+
if (isRecord$1(node)) {
|
|
1339
|
+
const elementTypes = getNodeArrayValue(node, "elementTypes") ?? [];
|
|
1340
|
+
score = 1;
|
|
1341
|
+
for (const element of elementTypes) {
|
|
1342
|
+
if (element.type === "TSRestType" || element.type === "TSOptionalType") continue;
|
|
1343
|
+
score = addStructuralScore(score, element, nextDepth, config, cache, depthMultiplierCache, ceiling);
|
|
1344
|
+
}
|
|
1345
|
+
score = addScore(score, 1.5 * elementTypes.length, config, ceiling);
|
|
1346
|
+
}
|
|
1361
1347
|
break;
|
|
1362
1348
|
case "TSTypeLiteral":
|
|
1363
|
-
|
|
1349
|
+
if (isRecord$1(node)) {
|
|
1350
|
+
const members = getNodeArrayValue(node, "members") ?? [];
|
|
1351
|
+
score = 2 + members.length * .5;
|
|
1352
|
+
score = addNestedTypeAnnotationScores(score, members, nextDepth, config, cache, depthMultiplierCache, ceiling);
|
|
1353
|
+
}
|
|
1364
1354
|
break;
|
|
1365
1355
|
case "TSTypeReference":
|
|
1366
|
-
score =
|
|
1356
|
+
score = 2;
|
|
1357
|
+
if (isRecord$1(node)) {
|
|
1358
|
+
const typeArguments = getNodeValue(node, "typeArguments");
|
|
1359
|
+
const parameters = typeArguments !== void 0 && isRecord$1(typeArguments) ? getNodeArrayValue(typeArguments, "params") ?? [] : [];
|
|
1360
|
+
for (const parameter of parameters) score = addStructuralScore(score, parameter, nextDepth, config, cache, depthMultiplierCache, ceiling, 2);
|
|
1361
|
+
}
|
|
1367
1362
|
break;
|
|
1368
1363
|
case "TSUnionType":
|
|
1369
|
-
|
|
1364
|
+
if (isRecord$1(node)) {
|
|
1365
|
+
const types = getNodeArrayValue(node, "types") ?? [];
|
|
1366
|
+
for (const type of types) score = addStructuralScore(score, type, nextDepth, config, cache, depthMultiplierCache, ceiling);
|
|
1367
|
+
score = addScore(score, 2 * (types.length - 1), config, ceiling);
|
|
1368
|
+
}
|
|
1370
1369
|
break;
|
|
1371
1370
|
default: score = 1;
|
|
1372
1371
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pobammer-ts/small-rules",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Various Oxlint-native rules for linting roblox-ts projects.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lint",
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
"jiti": "2.7.0",
|
|
107
107
|
"jscpd": "5.0.7",
|
|
108
108
|
"knip": "6.16.1",
|
|
109
|
-
"oxfmt": "0.
|
|
109
|
+
"oxfmt": "0.55.0",
|
|
110
110
|
"oxlint": "1.69.0",
|
|
111
111
|
"oxlint-tsgolint": "0.23.0",
|
|
112
112
|
"package-manager-detector": "1.6.0",
|