create-newt-app 0.26.1 → 0.29.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 (25) hide show
  1. package/dist/index.d.ts +5 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +307 -128
  4. package/dist/index.js.map +1 -1
  5. package/dist/static/anti-slop/static/LICENSE +21 -0
  6. package/dist/static/anti-slop/static/index.ts +41 -0
  7. package/dist/static/anti-slop/static/rules/no-chained-type-assertions.ts +77 -0
  8. package/dist/static/anti-slop/static/rules/no-conditional-empty-object-spread.ts +49 -0
  9. package/dist/static/anti-slop/static/rules/no-known-value-widening.ts +247 -0
  10. package/dist/static/anti-slop/static/rules/no-module-mocking.ts +91 -0
  11. package/dist/static/anti-slop/static/rules/no-object-parameters.ts +126 -0
  12. package/dist/static/anti-slop/static/rules/no-reflect-apply.ts +28 -0
  13. package/dist/static/anti-slop/static/rules/no-reflect-get.ts +28 -0
  14. package/dist/static/anti-slop/static/rules/no-runtime-typeof.ts +67 -0
  15. package/dist/static/anti-slop/static/rules/no-shape-in-symbol-names.ts +39 -0
  16. package/dist/static/anti-slop/static/rules/no-unknown-parameters.ts +83 -0
  17. package/dist/static/anti-slop/static/rules/no-unknown-returns.ts +115 -0
  18. package/dist/static/anti-slop/static/rules/no-unknown-type-aliases.ts +70 -0
  19. package/dist/static/anti-slop/static/rules/no-unsafe-dictionary-type.ts +134 -0
  20. package/dist/static/anti-slop/static/rules/no-widen-then-assert.ts +366 -0
  21. package/dist/static/anti-slop/static/rules/require-safety-comment-for-type-assertion.ts +62 -0
  22. package/dist/static/anti-slop/static/shared/dictionary-types.ts +502 -0
  23. package/dist/static/anti-slop/static/shared/lexical-type-parameters.ts +61 -0
  24. package/dist/static/anti-slop/static/shared/reflect-method.ts +35 -0
  25. package/package.json +14 -3
package/dist/index.js CHANGED
@@ -10,8 +10,8 @@ import ejs from "ejs";
10
10
  import { existsSync, promises } from "fs";
11
11
  import path from "path";
12
12
  //#region package.json
13
- var version = "0.26.1";
14
- var engines = { "node": ">=20.9.0" };
13
+ var version = "0.29.0";
14
+ var engines = { "node": ">=24.0.0" };
15
15
  //#endregion
16
16
  //#region src/templates/root/index.ts
17
17
  const root$2 = { templates: [
@@ -36,7 +36,7 @@ const root$2 = { templates: [
36
36
  },
37
37
  "packageManager": "pnpm@9.0.0",
38
38
  "engines": {
39
- "node": ">=20.9.0"
39
+ "node": ">=24.0.0"
40
40
  }
41
41
  }`
42
42
  },
@@ -110,10 +110,12 @@ dist
110
110
  "inputs": ["$TURBO_DEFAULT$", ".env*"],
111
111
  "outputs": [".next/**", "!.next/cache/**"]
112
112
  },
113
- "lint": {
113
+ <% if (linter === "oxc") { %> "typecheck": {
114
+ "dependsOn": ["^build"]
115
+ },<% } else { %> "lint": {
114
116
  "dependsOn": ["^lint"],
115
117
  "env": ["NODE_ENV"]
116
- },
118
+ },<% } %>
117
119
  "test": {
118
120
  "dependsOn": ["^build"],
119
121
  "outputs": ["coverage/**"]
@@ -737,7 +739,7 @@ export const authClient: ReturnType<typeof createAuthClient> = createAuthClient(
737
739
  };
738
740
  //#endregion
739
741
  //#region src/templates/api/index.ts
740
- const api$2 = { templates: [
742
+ const api$1 = { templates: [
741
743
  {
742
744
  when: (s) => !s.nestDiOnly && s.deployment !== "spa" && s.deployment !== "custom-server",
743
745
  filename: "apps/api/package.json",
@@ -819,14 +821,14 @@ const api$2 = { templates: [
819
821
  "noFallthroughCasesInSwitch": false,
820
822
  "types": [<% if (testing === 'jest') { %>"jest", <% } %><% if (testing === 'vitest') { %>"vitest/globals", <% } %>"node"]
821
823
  },
822
- "exclude": ["vitest.config.ts", "vitest.config.e2e.ts", "node_modules", "dist"]
824
+ "exclude": ["vitest.config.mts", "vitest.config.e2e.mts", "node_modules", "dist"]
823
825
  }`
824
826
  },
825
827
  {
826
828
  filename: "apps/api/tsconfig.build.json",
827
829
  template: `{
828
830
  "extends": "./tsconfig.json",
829
- "exclude": ["node_modules", "test", "dist", "**/*spec.ts", "vitest.config.ts", "vitest.config.e2e.ts", "jest.config.ts"]
831
+ "exclude": ["node_modules", "test", "dist", "**/*spec.ts", "vitest.config.mts", "vitest.config.e2e.mts", "jest.config.ts"]
830
832
  }`
831
833
  },
832
834
  {
@@ -1246,7 +1248,7 @@ const dbPostgres = { templates: [
1246
1248
  ] };
1247
1249
  //#endregion
1248
1250
  //#region src/templates/ui/index.ts
1249
- const ui$2 = { templates: [
1251
+ const ui$1 = { templates: [
1250
1252
  {
1251
1253
  filename: "packages/ui/package.json",
1252
1254
  template: `{
@@ -1499,6 +1501,7 @@ const versions = {
1499
1501
  "@nestjs/serve-static": "^5.0.0",
1500
1502
  "@nestjs/testing": "^11.0.1",
1501
1503
  "@next/eslint-plugin-next": "^16.3.0",
1504
+ "@oxlint/plugins": "^1.74.0",
1502
1505
  "@shadcn/react": "^0.2.1",
1503
1506
  "@swc/core": "^1.10.0",
1504
1507
  "@tailwindcss/postcss": "^4.2.1",
@@ -1508,63 +1511,63 @@ const versions = {
1508
1511
  "@types/better-sqlite3": "^7.6.13",
1509
1512
  "@types/express": "^5.0.0",
1510
1513
  "@types/jest": "^30.0.0",
1511
- "@types/node": "^22.15.3",
1514
+ "@types/node": "^24.13.3",
1512
1515
  "@types/pg": "^8.11.13",
1513
1516
  "@types/react": "19.2.14",
1514
1517
  "@types/react-dom": "19.2.3",
1515
1518
  "@types/supertest": "^6.0.2",
1516
- "@vitest/coverage-v8": "^3.0.0",
1517
- "auth": "^1.5.5",
1519
+ "@vitest/coverage-v8": "^4.1.10",
1520
+ auth: "^1.5.5",
1518
1521
  "better-auth": "^1.2.8",
1519
1522
  "better-sqlite3": "^12.11.1",
1520
1523
  "class-variance-authority": "^0.7.1",
1521
- "clsx": "^2.1.1",
1522
- "cmdk": "^1.1.1",
1524
+ clsx: "^2.1.1",
1525
+ cmdk: "^1.1.1",
1523
1526
  "date-fns": "^4.2.1",
1524
- "dotenv": "^17.3.1",
1527
+ dotenv: "^17.3.1",
1525
1528
  "dotenv-cli": "^11.0.0",
1526
1529
  "embla-carousel-react": "^8.6.0",
1527
- "eslint": "^9.39.1",
1530
+ eslint: "^9.39.1",
1528
1531
  "eslint-config-prettier": "^10.1.1",
1529
1532
  "eslint-plugin-only-warn": "^1.1.0",
1530
1533
  "eslint-plugin-react": "^7.37.5",
1531
1534
  "eslint-plugin-react-hooks": "^5.2.0",
1532
1535
  "eslint-plugin-turbo": "^2.7.1",
1533
- "globals": "^16.5.0",
1536
+ globals: "^16.5.0",
1534
1537
  "input-otp": "^1.4.2",
1535
- "jest": "^30.0.0",
1536
- "kysely": "^0.28.2",
1538
+ jest: "^30.0.0",
1539
+ kysely: "^0.28.2",
1537
1540
  "lucide-react": "^1.16.0",
1538
- "next": "16.3.0",
1541
+ next: "16.3.0",
1539
1542
  "next-themes": "^0.4.6",
1540
- "oxfmt": "^0.59.0",
1541
- "oxlint": "^1.74.0",
1542
- "pg": "^8.14.1",
1543
- "prettier": "^3.7.4",
1544
- "react": "^19.2.4",
1543
+ oxfmt: "^0.59.0",
1544
+ oxlint: "^1.74.0",
1545
+ pg: "^8.14.1",
1546
+ prettier: "^3.7.4",
1547
+ react: "^19.2.4",
1545
1548
  "react-day-picker": "^10.0.1",
1546
1549
  "react-dom": "^19.2.4",
1547
1550
  "react-resizable-panels": "^4.11.1",
1548
- "recharts": "^3.8.0",
1551
+ recharts: "^3.8.0",
1549
1552
  "reflect-metadata": "^0.2.2",
1550
- "rxjs": "^7.8.1",
1551
- "shadcn": "^4.7.0",
1552
- "sonner": "^2.0.7",
1553
+ rxjs: "^7.8.1",
1554
+ shadcn: "^4.7.0",
1555
+ sonner: "^2.0.7",
1553
1556
  "source-map-support": "^0.5.21",
1554
- "supertest": "^7.0.0",
1557
+ supertest: "^7.0.0",
1555
1558
  "tailwind-merge": "^3.6.0",
1556
- "tailwindcss": "^4.2.1",
1559
+ tailwindcss: "^4.2.1",
1557
1560
  "ts-jest": "^29.2.5",
1558
1561
  "ts-loader": "^9.5.2",
1559
1562
  "ts-node": "^10.9.2",
1560
1563
  "tsconfig-paths": "^4.2.0",
1561
- "tsx": "^4.19.4",
1562
- "turbo": "^2.8.16",
1564
+ tsx: "^4.19.4",
1565
+ turbo: "^2.8.16",
1563
1566
  "tw-animate-css": "^1.4.0",
1564
- "typescript": "6.0.2",
1567
+ typescript: "6.0.2",
1565
1568
  "typescript-eslint": "^8.50.0",
1566
1569
  "unplugin-swc": "^1.5.9",
1567
- "vitest": "^3.0.0"
1570
+ vitest: "^4.1.10"
1568
1571
  };
1569
1572
  //#endregion
1570
1573
  //#region src/templates/shadcn-ui/index.ts
@@ -3048,7 +3051,6 @@ function Calendar({
3048
3051
  ...classNames,
3049
3052
  }}
3050
3053
  components={{
3051
- // eslint-disable-next-line react/prop-types
3052
3054
  Root: ({ className, rootRef, ...props }) => {
3053
3055
  return (
3054
3056
  <div
@@ -3059,7 +3061,6 @@ function Calendar({
3059
3061
  />
3060
3062
  )
3061
3063
  },
3062
- // eslint-disable-next-line react/prop-types
3063
3064
  Chevron: ({ className, orientation, ...props }) => {
3064
3065
  if (orientation === "left") {
3065
3066
  return (
@@ -3881,7 +3882,7 @@ function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
3881
3882
  <CheckboxPrimitive.Root
3882
3883
  data-slot="checkbox"
3883
3884
  className={cn(
3884
- "peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary",
3885
+ "peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors outline-none group-has-disabled/field:opacity-50 group-has-[:focus-visible]/field-label:ring-0 group-has-[:focus-visible]/field-label:not-data-checked:border-input after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground group-has-[:focus-visible]/field-label:data-checked:border-primary dark:data-checked:bg-primary",
3885
3886
  className
3886
3887
  )}
3887
3888
  {...props}
@@ -5597,7 +5598,7 @@ function FieldLabel({
5597
5598
  <Label
5598
5599
  data-slot="field-label"
5599
5600
  className={cn(
5600
- "group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50 has-data-checked:border-primary/30 has-data-checked:bg-primary/5 has-[>[data-slot=field]]:rounded-lg has-[>[data-slot=field]]:border *:data-[slot=field]:p-2.5 dark:has-data-checked:border-primary/20 dark:has-data-checked:bg-primary/10",
5601
+ "group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50 has-data-checked:border-primary/30 has-data-checked:bg-primary/5 has-[>[data-slot=field]]:rounded-lg has-[>[data-slot=field]]:border has-[>[data-slot=field]]:not-has-[:disabled,[data-disabled]]:hover:bg-muted/50 has-[>[data-slot=field]]:has-[:focus-visible]:border-ring has-[>[data-slot=field]]:has-[:focus-visible]:ring-3 has-[>[data-slot=field]]:has-[:focus-visible]:ring-ring/50 *:data-[slot=field]:p-2.5 dark:has-data-checked:border-primary/20 dark:has-data-checked:bg-primary/10",
5601
5602
  "has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col",
5602
5603
  className
5603
5604
  )}
@@ -7285,7 +7286,7 @@ function RadioGroupItem({ className, ...props }: RadioPrimitive.Root.Props) {
7285
7286
  <RadioPrimitive.Root
7286
7287
  data-slot="radio-group-item"
7287
7288
  className={cn(
7288
- "group/radio-group-item peer relative flex aspect-square size-4 shrink-0 rounded-full border border-input outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary",
7289
+ "group/radio-group-item peer relative flex aspect-square size-4 shrink-0 rounded-full border border-input outline-none group-has-[:focus-visible]/field-label:ring-0 group-has-[:focus-visible]/field-label:not-data-checked:border-input after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground group-has-[:focus-visible]/field-label:data-checked:border-primary dark:data-checked:bg-primary",
7289
7290
  className
7290
7291
  )}
7291
7292
  {...props}
@@ -8665,7 +8666,7 @@ function Switch({
8665
8666
  data-slot="switch"
8666
8667
  data-size={size}
8667
8668
  className={cn(
8668
- "peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-unchecked:bg-input dark:data-unchecked:bg-input/80 data-disabled:cursor-not-allowed data-disabled:opacity-50",
8669
+ "peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none group-has-[:focus-visible]/field-label:border-transparent group-has-[:focus-visible]/field-label:ring-0 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-unchecked:bg-input dark:data-unchecked:bg-input/80 data-disabled:cursor-not-allowed data-disabled:opacity-50",
8669
8670
  className
8670
8671
  )}
8671
8672
  {...props}
@@ -10027,6 +10028,7 @@ export const config = [
10027
10028
  ...pluginReactHooks.configs.recommended.rules,
10028
10029
  // React scope no longer necessary with new JSX transform.
10029
10030
  "react/react-in-jsx-scope": "off",
10031
+ "react/prop-types": "off",
10030
10032
  },
10031
10033
  },
10032
10034
  ];`
@@ -10092,16 +10094,13 @@ export default config;`
10092
10094
  //#region src/templates/root/templates/prettierrc.ts
10093
10095
  var prettierrc_default = {
10094
10096
  filename: ".prettierrc",
10095
- template: `{
10096
- "singleQuote": true,
10097
- "trailingComma": "all"
10098
- }`
10097
+ template: `{}`
10099
10098
  };
10100
10099
  //#endregion
10101
10100
  //#region src/templates/eslint-config/index.ts
10102
10101
  const web$1 = "apps/web";
10103
- const api$1 = "apps/api";
10104
- const ui$1 = "packages/ui";
10102
+ const api = "apps/api";
10103
+ const ui = "packages/ui";
10105
10104
  const root$1 = "";
10106
10105
  const eslintConfig = {
10107
10106
  templates: [
@@ -10129,49 +10128,49 @@ const eslintConfig = {
10129
10128
  },
10130
10129
  {
10131
10130
  package: "@eslint/eslintrc",
10132
- module: api$1,
10131
+ module: api,
10133
10132
  version: versions["@eslint/eslintrc"],
10134
10133
  dev: true
10135
10134
  },
10136
10135
  {
10137
10136
  package: "@eslint/js",
10138
- module: api$1,
10137
+ module: api,
10139
10138
  version: versions["@eslint/js"],
10140
10139
  dev: true
10141
10140
  },
10142
10141
  {
10143
10142
  package: "eslint",
10144
- module: api$1,
10143
+ module: api,
10145
10144
  version: versions.eslint,
10146
10145
  dev: true
10147
10146
  },
10148
10147
  {
10149
10148
  package: "eslint-config-prettier",
10150
- module: api$1,
10149
+ module: api,
10151
10150
  version: versions["eslint-config-prettier"],
10152
10151
  dev: true
10153
10152
  },
10154
10153
  {
10155
10154
  package: "globals",
10156
- module: api$1,
10155
+ module: api,
10157
10156
  version: versions.globals,
10158
10157
  dev: true
10159
10158
  },
10160
10159
  {
10161
10160
  package: "typescript-eslint",
10162
- module: api$1,
10161
+ module: api,
10163
10162
  version: versions["typescript-eslint"],
10164
10163
  dev: true
10165
10164
  },
10166
10165
  {
10167
10166
  package: "eslint",
10168
- module: ui$1,
10167
+ module: ui,
10169
10168
  version: versions.eslint,
10170
10169
  dev: true
10171
10170
  },
10172
10171
  {
10173
10172
  package: "@<%= projectName %>/eslint-config",
10174
- module: ui$1,
10173
+ module: ui,
10175
10174
  version: "workspace:*",
10176
10175
  dev: true
10177
10176
  },
@@ -10194,22 +10193,22 @@ const eslintConfig = {
10194
10193
  script: "eslint --max-warnings 0 && next typegen && tsc --noEmit"
10195
10194
  },
10196
10195
  {
10197
- module: api$1,
10196
+ module: api,
10198
10197
  name: "lint",
10199
10198
  script: `eslint "src/**/*.ts" --fix`
10200
10199
  },
10201
10200
  {
10202
- module: api$1,
10201
+ module: api,
10203
10202
  name: "lint:check",
10204
10203
  script: `eslint "src/**/*.ts"`
10205
10204
  },
10206
10205
  {
10207
- module: ui$1,
10206
+ module: ui,
10208
10207
  name: "lint",
10209
10208
  script: "eslint . --fix"
10210
10209
  },
10211
10210
  {
10212
- module: ui$1,
10211
+ module: ui,
10213
10212
  name: "lint:check",
10214
10213
  script: "eslint . --max-warnings 0"
10215
10214
  },
@@ -10233,7 +10232,48 @@ var oxlintrc_default = {
10233
10232
  "$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json",
10234
10233
  "categories": {
10235
10234
  "correctness": "error"
10236
- }
10235
+ }<% if (antiSlop) { %>,
10236
+ "ignorePatterns": ["tools/oxlint/anti-slop/**"],
10237
+ "jsPlugins": [{ "name": "anti-slop", "specifier": "./tools/oxlint/anti-slop/index.ts" }],
10238
+ "rules": {
10239
+ "anti-slop/no-chained-type-assertions": "error",
10240
+ "anti-slop/no-conditional-empty-object-spread": "error",
10241
+ "anti-slop/no-known-value-widening": "error",
10242
+ "anti-slop/no-module-mocking": "error",
10243
+ "anti-slop/no-object-parameters": "error",
10244
+ "anti-slop/no-reflect-apply": "error",
10245
+ "anti-slop/no-reflect-get": "error",
10246
+ "anti-slop/no-runtime-typeof": "error",
10247
+ "anti-slop/no-shape-in-symbol-names": "error",
10248
+ "anti-slop/no-unknown-parameters": "error",
10249
+ "anti-slop/no-unknown-returns": "error",
10250
+ "anti-slop/no-unknown-type-aliases": "error",
10251
+ "anti-slop/no-unsafe-dictionary-type": "error",
10252
+ "anti-slop/no-widen-then-assert": "error",
10253
+ "anti-slop/require-safety-comment-for-type-assertion": "error"
10254
+ }<% if (shadcn) { %>,
10255
+ "overrides": [
10256
+ {
10257
+ "files": ["packages/ui/src/components/**"],
10258
+ "rules": {
10259
+ "anti-slop/no-chained-type-assertions": "off",
10260
+ "anti-slop/no-conditional-empty-object-spread": "off",
10261
+ "anti-slop/no-known-value-widening": "off",
10262
+ "anti-slop/no-module-mocking": "off",
10263
+ "anti-slop/no-object-parameters": "off",
10264
+ "anti-slop/no-reflect-apply": "off",
10265
+ "anti-slop/no-reflect-get": "off",
10266
+ "anti-slop/no-runtime-typeof": "off",
10267
+ "anti-slop/no-shape-in-symbol-names": "off",
10268
+ "anti-slop/no-unknown-parameters": "off",
10269
+ "anti-slop/no-unknown-returns": "off",
10270
+ "anti-slop/no-unknown-type-aliases": "off",
10271
+ "anti-slop/no-unsafe-dictionary-type": "off",
10272
+ "anti-slop/no-widen-then-assert": "off",
10273
+ "anti-slop/require-safety-comment-for-type-assertion": "off"
10274
+ }
10275
+ }
10276
+ ]<% } %><% } %>
10237
10277
  }`
10238
10278
  };
10239
10279
  //#endregion
@@ -10242,85 +10282,187 @@ var oxfmtrc_default = {
10242
10282
  filename: ".oxfmtrc.json",
10243
10283
  template: `{
10244
10284
  "$schema": "./node_modules/oxfmt/configuration_schema.json",
10245
- "ignorePatterns": []
10285
+ "ignorePatterns": [<% if (antiSlop) { %>"tools/oxlint/anti-slop/"<% } %>]
10246
10286
  }`
10247
10287
  };
10248
10288
  //#endregion
10249
10289
  //#region src/templates/oxc/index.ts
10250
10290
  const web = "apps/web";
10251
- const api = "apps/api";
10252
- const ui = "packages/ui";
10253
10291
  const root = "";
10254
10292
  const oxc = {
10255
10293
  templates: [oxlintrc_default, oxfmtrc_default],
10256
- packages: [
10294
+ packages: [{
10295
+ package: "oxlint",
10296
+ module: root,
10297
+ version: versions.oxlint,
10298
+ dev: true
10299
+ }, {
10300
+ package: "oxfmt",
10301
+ module: root,
10302
+ version: versions.oxfmt,
10303
+ dev: true
10304
+ }],
10305
+ scripts: [
10257
10306
  {
10258
- package: "oxlint",
10259
10307
  module: web,
10260
- version: versions.oxlint,
10261
- dev: true
10308
+ name: "typecheck",
10309
+ script: "next typegen && tsc --noEmit"
10262
10310
  },
10263
10311
  {
10264
- package: "oxlint",
10265
- module: api,
10266
- version: versions.oxlint,
10267
- dev: true
10312
+ module: root,
10313
+ name: "lint",
10314
+ script: "oxlint --fix"
10268
10315
  },
10269
10316
  {
10270
- package: "oxlint",
10271
- module: ui,
10272
- version: versions.oxlint,
10273
- dev: true
10317
+ module: root,
10318
+ name: "typecheck",
10319
+ script: "turbo run typecheck"
10274
10320
  },
10275
10321
  {
10276
- package: "oxfmt",
10277
10322
  module: root,
10278
- version: versions.oxfmt,
10279
- dev: true
10323
+ name: "lint:check",
10324
+ script: "oxlint"
10325
+ },
10326
+ {
10327
+ module: root,
10328
+ name: "format",
10329
+ script: "oxfmt"
10330
+ },
10331
+ {
10332
+ module: root,
10333
+ name: "format:check",
10334
+ script: "oxfmt --check"
10280
10335
  }
10281
- ],
10282
- scripts: [
10336
+ ]
10337
+ };
10338
+ //#endregion
10339
+ //#region src/templates/anti-slop/templates/plugin-package-json.ts
10340
+ var plugin_package_json_default = {
10341
+ filename: "tools/oxlint/anti-slop/package.json",
10342
+ template: `{
10343
+ "type": "module"
10344
+ }`
10345
+ };
10346
+ //#endregion
10347
+ //#region src/templates/anti-slop/templates/plugin-readme.ts
10348
+ var plugin_readme_default = {
10349
+ filename: "tools/oxlint/anti-slop/README.md",
10350
+ template: `# anti-slop
10351
+
10352
+ Oxlint rules that reject low-evidence TypeScript patterns, vendored from
10353
+ [dmmulroy/anti-slop](https://github.com/dmmulroy/anti-slop) at \`6d538555cb15\` (MIT, see LICENSE).
10354
+
10355
+ Upstream ships these to be vendored rather than depended on, so these files are
10356
+ yours: read them, change the messages, delete the rules you disagree with.
10357
+
10358
+ \`.oxlintrc.json\` registers the plugin and turns every rule on as an error.
10359
+ Turn one off there:
10360
+
10361
+ \`\`\`json
10362
+ {
10363
+ "rules": {
10364
+ "anti-slop/no-runtime-typeof": "off"
10365
+ }
10366
+ }
10367
+ \`\`\`
10368
+
10369
+ Vendored shadcn components under \`packages/ui/src/components\` are exempt, since
10370
+ they are upstream code you re-pull rather than write.
10371
+ `
10372
+ };
10373
+ //#endregion
10374
+ //#region src/templates/anti-slop/index.ts
10375
+ const plugin = "tools/oxlint/anti-slop";
10376
+ const antiSlop = {
10377
+ templates: [plugin_package_json_default, plugin_readme_default],
10378
+ staticFiles: [
10283
10379
  {
10284
- module: web,
10285
- name: "lint",
10286
- script: "oxlint --fix && next typegen && tsc --noEmit"
10380
+ src: "anti-slop/static/LICENSE",
10381
+ filename: `${plugin}/LICENSE`
10287
10382
  },
10288
10383
  {
10289
- module: web,
10290
- name: "lint:check",
10291
- script: "oxlint && next typegen && tsc --noEmit"
10384
+ src: "anti-slop/static/index.ts",
10385
+ filename: `${plugin}/index.ts`
10292
10386
  },
10293
10387
  {
10294
- module: api,
10295
- name: "lint",
10296
- script: "oxlint src --fix"
10388
+ src: "anti-slop/static/rules/no-chained-type-assertions.ts",
10389
+ filename: `${plugin}/rules/no-chained-type-assertions.ts`
10297
10390
  },
10298
10391
  {
10299
- module: api,
10300
- name: "lint:check",
10301
- script: "oxlint src"
10392
+ src: "anti-slop/static/rules/no-conditional-empty-object-spread.ts",
10393
+ filename: `${plugin}/rules/no-conditional-empty-object-spread.ts`
10302
10394
  },
10303
10395
  {
10304
- module: ui,
10305
- name: "lint",
10306
- script: "oxlint --fix"
10396
+ src: "anti-slop/static/rules/no-known-value-widening.ts",
10397
+ filename: `${plugin}/rules/no-known-value-widening.ts`
10307
10398
  },
10308
10399
  {
10309
- module: ui,
10310
- name: "lint:check",
10311
- script: "oxlint"
10400
+ src: "anti-slop/static/rules/no-module-mocking.ts",
10401
+ filename: `${plugin}/rules/no-module-mocking.ts`
10312
10402
  },
10313
10403
  {
10314
- module: root,
10315
- name: "format",
10316
- script: "oxfmt"
10404
+ src: "anti-slop/static/rules/no-object-parameters.ts",
10405
+ filename: `${plugin}/rules/no-object-parameters.ts`
10317
10406
  },
10318
10407
  {
10319
- module: root,
10320
- name: "format:check",
10321
- script: "oxfmt --check"
10408
+ src: "anti-slop/static/rules/no-reflect-apply.ts",
10409
+ filename: `${plugin}/rules/no-reflect-apply.ts`
10410
+ },
10411
+ {
10412
+ src: "anti-slop/static/rules/no-reflect-get.ts",
10413
+ filename: `${plugin}/rules/no-reflect-get.ts`
10414
+ },
10415
+ {
10416
+ src: "anti-slop/static/rules/no-runtime-typeof.ts",
10417
+ filename: `${plugin}/rules/no-runtime-typeof.ts`
10418
+ },
10419
+ {
10420
+ src: "anti-slop/static/rules/no-shape-in-symbol-names.ts",
10421
+ filename: `${plugin}/rules/no-shape-in-symbol-names.ts`
10422
+ },
10423
+ {
10424
+ src: "anti-slop/static/rules/no-unknown-parameters.ts",
10425
+ filename: `${plugin}/rules/no-unknown-parameters.ts`
10426
+ },
10427
+ {
10428
+ src: "anti-slop/static/rules/no-unknown-returns.ts",
10429
+ filename: `${plugin}/rules/no-unknown-returns.ts`
10430
+ },
10431
+ {
10432
+ src: "anti-slop/static/rules/no-unknown-type-aliases.ts",
10433
+ filename: `${plugin}/rules/no-unknown-type-aliases.ts`
10434
+ },
10435
+ {
10436
+ src: "anti-slop/static/rules/no-unsafe-dictionary-type.ts",
10437
+ filename: `${plugin}/rules/no-unsafe-dictionary-type.ts`
10438
+ },
10439
+ {
10440
+ src: "anti-slop/static/rules/no-widen-then-assert.ts",
10441
+ filename: `${plugin}/rules/no-widen-then-assert.ts`
10442
+ },
10443
+ {
10444
+ src: "anti-slop/static/rules/require-safety-comment-for-type-assertion.ts",
10445
+ filename: `${plugin}/rules/require-safety-comment-for-type-assertion.ts`
10446
+ },
10447
+ {
10448
+ src: "anti-slop/static/shared/dictionary-types.ts",
10449
+ filename: `${plugin}/shared/dictionary-types.ts`
10450
+ },
10451
+ {
10452
+ src: "anti-slop/static/shared/lexical-type-parameters.ts",
10453
+ filename: `${plugin}/shared/lexical-type-parameters.ts`
10454
+ },
10455
+ {
10456
+ src: "anti-slop/static/shared/reflect-method.ts",
10457
+ filename: `${plugin}/shared/reflect-method.ts`
10322
10458
  }
10323
- ]
10459
+ ],
10460
+ packages: [{
10461
+ package: "@oxlint/plugins",
10462
+ module: "",
10463
+ version: versions["@oxlint/plugins"],
10464
+ dev: true
10465
+ }]
10324
10466
  };
10325
10467
  //#endregion
10326
10468
  //#region src/templates/typescript-config/index.ts
@@ -10411,13 +10553,15 @@ export default {
10411
10553
  {
10412
10554
  filename: "apps/api/test/jest-e2e.json",
10413
10555
  template: `{
10414
- "moduleFileExtensions": ["js", "json", "ts"],
10556
+ "moduleFileExtensions": ["js", "mjs", "json", "ts"],
10415
10557
  "rootDir": ".",
10416
10558
  "testEnvironment": "node",
10417
10559
  "testRegex": ".e2e-spec.ts$",
10560
+ "extensionsToTreatAsEsm": [".ts"],
10418
10561
  "transform": {
10419
- "^.+\\\\.(t|j)s$": "ts-jest"
10420
- }
10562
+ "^.+\\\\.ts$": ["ts-jest", { "useESM": true, "tsconfig": { "module": "esnext" } }]
10563
+ },
10564
+ "transformIgnorePatterns": ["node_modules/(?!.*\\\\.mjs$)"]
10421
10565
  }`
10422
10566
  },
10423
10567
  {
@@ -10440,11 +10584,11 @@ describe('AppController (e2e)', () => {
10440
10584
  await app.init();
10441
10585
  });
10442
10586
 
10443
- it('/ (GET)', () => {
10587
+ it('/hello (GET)', () => {
10444
10588
  return request(app.getHttpServer())
10445
- .get('/')
10589
+ .get('/hello')
10446
10590
  .expect(200)
10447
- .expect('Hello World!');
10591
+ .expect({ message: 'Hello from Nest' });
10448
10592
  });
10449
10593
  });`
10450
10594
  },
@@ -10519,7 +10663,7 @@ module.exports = {
10519
10663
  {
10520
10664
  module: "apps/api",
10521
10665
  name: "test:e2e",
10522
- script: "jest --config ./test/jest-e2e.json"
10666
+ script: "NODE_OPTIONS=--experimental-vm-modules jest --config ./test/jest-e2e.json"
10523
10667
  }
10524
10668
  ]
10525
10669
  };
@@ -10528,7 +10672,7 @@ module.exports = {
10528
10672
  const testingVitest = {
10529
10673
  templates: [
10530
10674
  {
10531
- filename: "apps/api/vitest.config.ts",
10675
+ filename: "apps/api/vitest.config.mts",
10532
10676
  template: `import swc from 'unplugin-swc';
10533
10677
  import { defineConfig } from 'vitest/config';
10534
10678
 
@@ -10545,7 +10689,7 @@ export default defineConfig({
10545
10689
  });`
10546
10690
  },
10547
10691
  {
10548
- filename: "apps/api/vitest.config.e2e.ts",
10692
+ filename: "apps/api/vitest.config.e2e.mts",
10549
10693
  template: `import swc from 'unplugin-swc';
10550
10694
  import { defineConfig } from 'vitest/config';
10551
10695
 
@@ -10579,11 +10723,11 @@ describe('AppController (e2e)', () => {
10579
10723
  await app.init();
10580
10724
  });
10581
10725
 
10582
- it('/ (GET)', () => {
10726
+ it('/hello (GET)', () => {
10583
10727
  return request(app.getHttpServer())
10584
- .get('/')
10728
+ .get('/hello')
10585
10729
  .expect(200)
10586
- .expect('Hello World!');
10730
+ .expect({ message: 'Hello from Nest' });
10587
10731
  });
10588
10732
  });`
10589
10733
  }
@@ -10638,7 +10782,7 @@ describe('AppController (e2e)', () => {
10638
10782
  {
10639
10783
  module: "apps/api",
10640
10784
  name: "test:e2e",
10641
- script: "vitest run --config ./vitest.config.e2e.ts"
10785
+ script: "vitest run --config ./vitest.config.e2e.mts"
10642
10786
  }
10643
10787
  ]
10644
10788
  };
@@ -12443,7 +12587,7 @@ function getStaticFilePath(name) {
12443
12587
  return fileURLToPath(new URL(`./static/${name}`, import.meta.url));
12444
12588
  }
12445
12589
  function selectModules(selection) {
12446
- const { deployment, nestDiOnly: nestDiOnly$1, todoExample, shadcn, database, linter, testing } = selection;
12590
+ const { deployment, nestDiOnly: nestDiOnly$1, todoExample, shadcn, database, linter, testing, extras } = selection;
12447
12591
  const deploymentModule = deployment === "standalone" ? deploymentStandalone : deployment === "custom-server" ? singleProcessCustomServer : deployment === "spa" ? singleProcessStaticExport : null;
12448
12592
  const webModule = deployment === "spa" ? {
12449
12593
  ...web$2,
@@ -12452,11 +12596,12 @@ function selectModules(selection) {
12452
12596
  return [
12453
12597
  root$2,
12454
12598
  webModule,
12455
- api$2,
12599
+ api$1,
12456
12600
  database === "postgres" ? dbPostgres : dbSqlite,
12457
12601
  auth,
12458
- shadcn ? shadcnUi : ui$2,
12602
+ shadcn ? shadcnUi : ui$1,
12459
12603
  linter === "oxc" ? oxc : eslintConfig,
12604
+ ...extras.includes("anti-slop") ? [antiSlop] : [],
12460
12605
  typescriptConfig,
12461
12606
  testing === "vitest" ? testingVitest : testingJest,
12462
12607
  ...deploymentModule ? [deploymentModule] : [],
@@ -12562,6 +12707,13 @@ function validateFlagValue(flag, value, allowed) {
12562
12707
  error: `Invalid value "${value}" for ${flag}. Valid choices: ${allowed.join(", ")}.`
12563
12708
  };
12564
12709
  }
12710
+ function validateExtrasCombo(extras, linter) {
12711
+ if (extras.includes("anti-slop") && linter !== "oxc") return {
12712
+ valid: false,
12713
+ error: "--extras anti-slop needs --linter oxc.\nanti-slop is a set of oxlint rules, and the eslint option installs neither oxlint\nnor a config to register them in. Add --linter oxc, or drop the extra."
12714
+ };
12715
+ return { valid: true };
12716
+ }
12565
12717
  function validateDeploymentCombo(deployment, nestDiOnly) {
12566
12718
  if (deployment === "spa" && nestDiOnly) return {
12567
12719
  valid: false,
@@ -12633,6 +12785,9 @@ async function scaffold(modules, options) {
12633
12785
  testing: options.testing,
12634
12786
  database: options.database,
12635
12787
  deployment: options.deployment,
12788
+ linter: options.linter,
12789
+ antiSlop: options.antiSlop,
12790
+ shadcn: options.selection.shadcn,
12636
12791
  authSecret: randomBytes(32).toString("base64url"),
12637
12792
  versions
12638
12793
  };
@@ -12677,6 +12832,7 @@ const DEPLOYMENT_CHOICES = [
12677
12832
  "custom-server",
12678
12833
  "spa"
12679
12834
  ];
12835
+ const EXTRAS_CHOICES = ["anti-slop"];
12680
12836
  var TaskBuilder = class {
12681
12837
  tasks = [];
12682
12838
  add(task) {
@@ -12732,6 +12888,15 @@ async function doInit(options) {
12732
12888
  }],
12733
12889
  initialValue: "eslint"
12734
12890
  }),
12891
+ extras: ({ results }) => results.linter === "oxc" ? p.multiselect({
12892
+ message: "Extras?",
12893
+ options: [{
12894
+ value: "anti-slop",
12895
+ label: "anti-slop",
12896
+ hint: "oxlint rules that reject low-evidence TypeScript"
12897
+ }],
12898
+ required: false
12899
+ }) : void 0,
12735
12900
  nestDiOnly: () => p.confirm({
12736
12901
  message: "Use NestJS for dependency injection only?",
12737
12902
  initialValue: false
@@ -12741,7 +12906,7 @@ async function doInit(options) {
12741
12906
  initialValue: true
12742
12907
  }),
12743
12908
  deployment: ({ results }) => p.select({
12744
- message: "Deployment extras?",
12909
+ message: "Deployment?",
12745
12910
  options: [
12746
12911
  {
12747
12912
  value: "none",
@@ -12783,9 +12948,12 @@ async function doInit(options) {
12783
12948
  const linter = options.nonInteractive ? options.linter : group.linter ?? "eslint";
12784
12949
  const deployment = options.nonInteractive ? options.deployment : group.deployment ?? "none";
12785
12950
  const nestDiOnly = options.nonInteractive ? options.nestDiOnly : group.nestDiOnly ?? false;
12786
- const todoExample = options.nonInteractive ? !options.bare : group.todoExample ?? true;
12951
+ const todoExample = options.nonInteractive ? options.includeExample : group.todoExample ?? true;
12952
+ const extras = options.nonInteractive ? options.extras : group.extras ?? [];
12787
12953
  const deploymentCombo = validateDeploymentCombo(deployment, nestDiOnly);
12788
12954
  if (!deploymentCombo.valid) throw new Error(deploymentCombo.error);
12955
+ const extrasCombo = validateExtrasCombo(extras, linter);
12956
+ if (!extrasCombo.valid) throw new Error(extrasCombo.error);
12789
12957
  const selection = {
12790
12958
  deployment,
12791
12959
  nestDiOnly,
@@ -12793,7 +12961,8 @@ async function doInit(options) {
12793
12961
  shadcn: useShadcn,
12794
12962
  database,
12795
12963
  linter,
12796
- testing
12964
+ testing,
12965
+ extras
12797
12966
  };
12798
12967
  const allModules = selectModules(selection);
12799
12968
  const name = group.name ?? options.name ?? "";
@@ -12806,6 +12975,8 @@ async function doInit(options) {
12806
12975
  testing,
12807
12976
  database,
12808
12977
  deployment,
12978
+ linter,
12979
+ antiSlop: extras.includes("anti-slop"),
12809
12980
  selection
12810
12981
  });
12811
12982
  return "Scaffolded.";
@@ -12847,7 +13018,7 @@ async function doInit(options) {
12847
13018
  }
12848
13019
  }
12849
13020
  const program = new Command();
12850
- program.name("create-newt-app").version(version).description("Create a new newt-app monorepo").argument("[name]").option("-ni, --no-install", "Skip pnpm install", true).option("-ng, --no-git", "Skip git initialization", true).option("--shadcn", "Include shadcn/ui", false).option("--testing <framework>", "Testing framework: vitest or jest", "jest").option("--database <database>", "Database: sqlite or postgres", "sqlite").option("--linter <linter>", "Linter: eslint or oxc", "eslint").option("--deployment <strategy>", "Deployment extras: standalone, custom-server, spa", "none").option("--nest-di-only", "Use NestJS for dependency injection only", false).option("--bare", "Skip the todo example", false).action(async (name, options, command) => {
13021
+ program.name("create-newt-app").version(version).description("Create a new newt-app monorepo").argument("[name]").option("-ni, --no-install", "Skip pnpm install", true).option("-ng, --no-git", "Skip git initialization", true).option("--shadcn", "Include shadcn/ui", false).option("--testing <framework>", "Testing framework: vitest or jest", "jest").option("--database <database>", "Database: sqlite or postgres", "sqlite").option("--linter <linter>", "Linter: eslint or oxc", "eslint").option("--deployment <strategy>", "Deployment: standalone, custom-server, spa", "none").option("--nest-di-only", "Use NestJS for dependency injection only", false).option("--include-example", "Include the todo example", false).option("--extras <list>", "Extras, comma-separated: anti-slop", "").action(async (name, options, command) => {
12851
13022
  intro(`Create a ${chalk.blue("newt")} app.`);
12852
13023
  const nonInteractive = [
12853
13024
  "shadcn",
@@ -12856,8 +13027,10 @@ program.name("create-newt-app").version(version).description("Create a new newt-
12856
13027
  "linter",
12857
13028
  "deployment",
12858
13029
  "nestDiOnly",
12859
- "bare"
13030
+ "includeExample",
13031
+ "extras"
12860
13032
  ].some((flag) => command.getOptionValueSource(flag) === "cli");
13033
+ const extras = options.extras.split(",").map((extra) => extra.trim()).filter(Boolean);
12861
13034
  const invalid = [
12862
13035
  {
12863
13036
  flag: "--testing",
@@ -12878,7 +13051,12 @@ program.name("create-newt-app").version(version).description("Create a new newt-
12878
13051
  flag: "--deployment",
12879
13052
  value: options.deployment,
12880
13053
  allowed: DEPLOYMENT_CHOICES
12881
- }
13054
+ },
13055
+ ...extras.map((extra) => ({
13056
+ flag: "--extras",
13057
+ value: extra,
13058
+ allowed: EXTRAS_CHOICES
13059
+ }))
12882
13060
  ].map(({ flag, value, allowed }) => validateFlagValue(flag, value, allowed)).find((result) => !result.valid);
12883
13061
  if (invalid) {
12884
13062
  console.error(`Error: ${invalid.error}`);
@@ -12895,7 +13073,8 @@ program.name("create-newt-app").version(version).description("Create a new newt-
12895
13073
  linter: options.linter,
12896
13074
  deployment: options.deployment,
12897
13075
  nestDiOnly: options.nestDiOnly,
12898
- bare: options.bare
13076
+ includeExample: options.includeExample,
13077
+ extras
12899
13078
  });
12900
13079
  });
12901
13080
  program.parse();