@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.
Files changed (3) hide show
  1. package/README.md +35 -0
  2. package/dist/index.js +81 -82
  3. 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 = addScore(score, calculateStructuralComplexity(typeAnnotation, depth, config, cache, depthMultiplierCache, ceiling), config, ceiling);
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.max(1, Math.log2(depth + 1));
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
- score = calculateArrayTypeComplexity(node, nextDepth, config, cache, depthMultiplierCache, ceiling);
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 = calculateConditionalTypeComplexity(node, nextDepth, config, cache, depthMultiplierCache, ceiling);
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 = calculateFunctionTypeComplexity(node, nextDepth, config, cache, depthMultiplierCache, ceiling);
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 = calculateInterfaceComplexity(node, nextDepth, config, cache, depthMultiplierCache, ceiling);
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
- score = calculateTypeListComplexity(node, nextDepth, (typeCount) => 3 * typeCount, config, cache, depthMultiplierCache, ceiling);
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 = calculateMappedTypeComplexity(node, nextDepth, config, cache, depthMultiplierCache, ceiling);
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
- score = calculateTupleTypeComplexity(node, nextDepth, config, cache, depthMultiplierCache, ceiling);
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
- score = calculateTypeLiteralComplexity(node, nextDepth, config, cache, depthMultiplierCache, ceiling);
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 = calculateTypeReferenceComplexity(node, nextDepth, config, cache, depthMultiplierCache, ceiling);
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
- score = calculateTypeListComplexity(node, nextDepth, (typeCount) => 2 * (typeCount - 1), config, cache, depthMultiplierCache, ceiling);
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.0.0",
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.54.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",