create-newt-app 0.32.1 → 0.33.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/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import { existsSync, promises } from "fs";
11
11
  import path from "path";
12
12
  import https from "node:https";
13
13
  //#region package.json
14
- var version = "0.32.1";
14
+ var version = "0.33.0";
15
15
  var engines = { "node": ">=24.0.0" };
16
16
  //#endregion
17
17
  //#region src/templates/root/index.ts
@@ -231,7 +231,7 @@ This version has breaking changes — APIs, conventions, and file structure may
231
231
  const web$1 = {
232
232
  templates: [
233
233
  {
234
- when: (s) => s.nest !== "di-only",
234
+ when: (s) => s.nest !== "di-only" && !s.stylex,
235
235
  filename: "apps/web/package.json",
236
236
  template: `{
237
237
  "name": "web",
@@ -369,6 +369,7 @@ const nextConfig = {
369
369
  export default nextConfig;`
370
370
  },
371
371
  {
372
+ when: (s) => !s.stylex,
372
373
  filename: "apps/web/postcss.config.mjs",
373
374
  template: `export { default } from "@<%= projectName %>/ui/postcss.config";`
374
375
  },
@@ -399,7 +400,7 @@ export default nextConfig;`
399
400
  }`
400
401
  },
401
402
  {
402
- when: (s) => !s.shadcn,
403
+ when: (s) => !s.shadcn && !s.stylex,
403
404
  filename: "apps/web/app/layout.tsx",
404
405
  template: `import type { Metadata } from "next";
405
406
  import localFont from "next/font/local";
@@ -442,7 +443,7 @@ export default function RootLayout({
442
443
  }`
443
444
  },
444
445
  {
445
- when: (s) => !s.todoExample && !s.shadcn,
446
+ when: (s) => !s.todoExample && !s.shadcn && !s.stylex,
446
447
  filename: "apps/web/app/page.tsx",
447
448
  template: `'use client';
448
449
 
@@ -543,7 +544,7 @@ export default function Providers({ children }: { children: React.ReactNode }) {
543
544
  }`
544
545
  },
545
546
  {
546
- when: (s) => !s.shadcn,
547
+ when: (s) => !s.shadcn && !s.stylex,
547
548
  filename: "apps/web/app/auth-form.tsx",
548
549
  template: `'use client';
549
550
 
@@ -1258,11 +1259,10 @@ const dbPostgres = { templates: [
1258
1259
  src_index_postgres_default
1259
1260
  ] };
1260
1261
  //#endregion
1261
- //#region src/templates/ui/index.ts
1262
- const ui$1 = { templates: [
1263
- {
1264
- filename: "packages/ui/package.json",
1265
- template: `{
1262
+ //#region src/templates/ui/templates/package-json.ts
1263
+ var package_json_default$4 = {
1264
+ filename: "packages/ui/package.json",
1265
+ template: `{
1266
1266
  "name": "@<%= projectName %>/ui",
1267
1267
  "version": "0.0.0",
1268
1268
  "private": true,
@@ -1294,10 +1294,12 @@ const ui$1 = { templates: [
1294
1294
  "tailwind-merge": "<%= versions["tailwind-merge"] %>"
1295
1295
  }
1296
1296
  }`
1297
- },
1298
- {
1299
- filename: "packages/ui/src/button.tsx",
1300
- template: `"use client";
1297
+ };
1298
+ //#endregion
1299
+ //#region src/templates/ui/templates/button.ts
1300
+ var button_default$2 = {
1301
+ filename: "packages/ui/src/button.tsx",
1302
+ template: `"use client";
1301
1303
 
1302
1304
  import { ReactNode } from "react";
1303
1305
  import { cn } from "./utils";
@@ -1329,10 +1331,12 @@ export const Button = ({ children, onClick, type = "button", disabled, className
1329
1331
  </button>
1330
1332
  );
1331
1333
  };`
1332
- },
1333
- {
1334
- filename: "packages/ui/src/link.tsx",
1335
- template: `import NextLink, { type LinkProps } from "next/link";
1334
+ };
1335
+ //#endregion
1336
+ //#region src/templates/ui/templates/link.ts
1337
+ var link_default$2 = {
1338
+ filename: "packages/ui/src/link.tsx",
1339
+ template: `import NextLink, { type LinkProps } from "next/link";
1336
1340
  import { type PropsWithChildren } from "react";
1337
1341
  import { cn } from "./utils";
1338
1342
 
@@ -1355,10 +1359,12 @@ export function Link({
1355
1359
  </NextLink>
1356
1360
  );
1357
1361
  }`
1358
- },
1359
- {
1360
- filename: "packages/ui/src/logo.tsx",
1361
- template: `import { cn } from "./utils";
1362
+ };
1363
+ //#endregion
1364
+ //#region src/templates/ui/templates/logo.ts
1365
+ var logo_default$2 = {
1366
+ filename: "packages/ui/src/logo.tsx",
1367
+ template: `import { cn } from "./utils";
1362
1368
 
1363
1369
  interface LogoProps {
1364
1370
  className?: string;
@@ -1381,19 +1387,23 @@ export function Logo({ className }: LogoProps) {
1381
1387
  </svg>
1382
1388
  );
1383
1389
  }`
1384
- },
1385
- {
1386
- filename: "packages/ui/src/utils.ts",
1387
- template: `import { clsx, type ClassValue } from "clsx";
1390
+ };
1391
+ //#endregion
1392
+ //#region src/templates/ui/templates/utils.ts
1393
+ var utils_default$1 = {
1394
+ filename: "packages/ui/src/utils.ts",
1395
+ template: `import { clsx, type ClassValue } from "clsx";
1388
1396
  import { twMerge } from "tailwind-merge";
1389
1397
 
1390
1398
  export function cn(...inputs: ClassValue[]) {
1391
1399
  return twMerge(clsx(inputs));
1392
1400
  }`
1393
- },
1394
- {
1395
- filename: "packages/ui/src/globals.css",
1396
- template: `@import 'tailwindcss';
1401
+ };
1402
+ //#endregion
1403
+ //#region src/templates/ui/templates/globals-css.ts
1404
+ var globals_css_default$2 = {
1405
+ filename: "packages/ui/src/globals.css",
1406
+ template: `@import 'tailwindcss';
1397
1407
  @source "../../../apps/**/*.{ts,tsx}";
1398
1408
  @source "../**/*.{ts,tsx}";
1399
1409
 
@@ -1430,20 +1440,24 @@ export function cn(...inputs: ClassValue[]) {
1430
1440
  border-color: var(--border);
1431
1441
  }
1432
1442
  }`
1433
- },
1434
- {
1435
- filename: "packages/ui/postcss.config.mjs",
1436
- template: `const config = {
1443
+ };
1444
+ //#endregion
1445
+ //#region src/templates/ui/templates/postcss-config.ts
1446
+ var postcss_config_default$2 = {
1447
+ filename: "packages/ui/postcss.config.mjs",
1448
+ template: `const config = {
1437
1449
  plugins: {
1438
1450
  "@tailwindcss/postcss": {},
1439
1451
  },
1440
1452
  };
1441
1453
 
1442
1454
  export default config;`
1443
- },
1444
- {
1445
- filename: "packages/ui/tsconfig.json",
1446
- template: `{
1455
+ };
1456
+ //#endregion
1457
+ //#region src/templates/ui/templates/tsconfig.ts
1458
+ var tsconfig_default$1 = {
1459
+ filename: "packages/ui/tsconfig.json",
1460
+ template: `{
1447
1461
  "extends": "@<%= projectName %>/typescript-config/react-library.json",
1448
1462
  "compilerOptions": {
1449
1463
  "outDir": "dist",
@@ -1452,11 +1466,24 @@ export default config;`
1452
1466
  "include": ["src"],
1453
1467
  "exclude": ["node_modules", "dist"]
1454
1468
  }`
1455
- }
1469
+ };
1470
+ //#endregion
1471
+ //#region src/templates/ui/index.ts
1472
+ const ui$1 = { templates: [
1473
+ package_json_default$4,
1474
+ button_default$2,
1475
+ link_default$2,
1476
+ logo_default$2,
1477
+ utils_default$1,
1478
+ globals_css_default$2,
1479
+ postcss_config_default$2,
1480
+ tsconfig_default$1
1456
1481
  ] };
1457
1482
  //#endregion
1458
1483
  //#region src/templates/versions.ts
1459
1484
  const versions = {
1485
+ "@babel/plugin-proposal-decorators": "^8.0.2",
1486
+ "@babel/plugin-transform-class-properties": "^8.0.1",
1460
1487
  "@base-ui/react": "^1.6.0",
1461
1488
  "@eslint/js": "^9.39.1",
1462
1489
  "@nestjs/cli": "^11.0.0",
@@ -1469,6 +1496,9 @@ const versions = {
1469
1496
  "@next/eslint-plugin-next": "^16.3.4",
1470
1497
  "@oxlint/plugins": "^1.74.0",
1471
1498
  "@shadcn/react": "^0.2.1",
1499
+ "@stylexjs/babel-plugin": "0.19.0",
1500
+ "@stylexjs/postcss-plugin": "0.19.0",
1501
+ "@stylexjs/stylex": "0.19.0",
1472
1502
  "@swc/core": "^1.10.0",
1473
1503
  "@tailwindcss/postcss": "^4.2.1",
1474
1504
  "@tanstack/react-form": "^1.28.5",
@@ -1484,6 +1514,7 @@ const versions = {
1484
1514
  "@types/supertest": "^6.0.2",
1485
1515
  "@vitest/coverage-v8": "^4.1.10",
1486
1516
  auth: "^1.5.5",
1517
+ "babel-plugin-transform-typescript-metadata": "^0.4.0",
1487
1518
  "better-auth": "^1.2.8",
1488
1519
  "better-sqlite3": "^12.11.1",
1489
1520
  "class-variance-authority": "^0.7.1",
@@ -9829,154 +9860,953 @@ export {
9829
9860
  }]
9830
9861
  };
9831
9862
  //#endregion
9832
- //#region src/templates/eslint-config/templates/package-json.ts
9833
- var package_json_default$1 = {
9834
- filename: "packages/eslint-config/package.json",
9835
- template: `{
9836
- "name": "@<%= projectName %>/eslint-config",
9863
+ //#region src/templates/stylex-ui/index.ts
9864
+ const stylexUi = { templates: [
9865
+ {
9866
+ filename: "packages/ui/package.json",
9867
+ template: `{
9868
+ "name": "@<%= projectName %>/ui",
9837
9869
  "version": "0.0.0",
9838
- "type": "module",
9839
9870
  "private": true,
9840
9871
  "exports": {
9841
- "./base": "./base.js",
9842
- "./next-js": "./next.js",
9843
- "./react-internal": "./react-internal.js"
9872
+ "./globals.css": "./src/globals.css",
9873
+ "./tokens.stylex": "./src/tokens.stylex.ts",
9874
+ "./*": "./src/*.tsx"
9875
+ },
9876
+ "scripts": {
9877
+ "typecheck": "tsc --noEmit"
9844
9878
  },
9845
9879
  "devDependencies": {
9846
- "@eslint/js": "<%= versions["@eslint/js"] %>",
9847
- "@next/eslint-plugin-next": "<%= versions["@next/eslint-plugin-next"] %>",
9848
- "eslint": "<%= versions.eslint %>",
9849
- "eslint-config-prettier": "<%= versions["eslint-config-prettier"] %>",
9850
- "eslint-plugin-only-warn": "<%= versions["eslint-plugin-only-warn"] %>",
9851
- "eslint-plugin-react": "<%= versions["eslint-plugin-react"] %>",
9852
- "eslint-plugin-react-hooks": "<%= versions["eslint-plugin-react-hooks"] %>",
9853
- "eslint-plugin-turbo": "<%= versions["eslint-plugin-turbo"] %>",
9854
- "globals": "<%= versions.globals %>",
9855
- "typescript": "<%= versions.typescript %>",
9856
- "typescript-eslint": "<%= versions["typescript-eslint"] %>"
9880
+ "@<%= projectName %>/typescript-config": "workspace:*",
9881
+ "@types/node": "<%= versions["@types/node"] %>",
9882
+ "@types/react": "<%= versions["@types/react"] %>",
9883
+ "@types/react-dom": "<%= versions["@types/react-dom"] %>",
9884
+ "typescript": "<%= versions.typescript %>"
9885
+ },
9886
+ "peerDependencies": {
9887
+ "next": ">=15.0.0",
9888
+ "react": ">=19.0.0",
9889
+ "react-dom": ">=19.0.0"
9890
+ },
9891
+ "dependencies": {
9892
+ "@stylexjs/stylex": "<%= versions["@stylexjs/stylex"] %>"
9857
9893
  }
9858
9894
  }`
9895
+ },
9896
+ {
9897
+ filename: "packages/ui/src/tokens.stylex.ts",
9898
+ template: `import * as stylex from "@stylexjs/stylex";
9899
+
9900
+ export const colors = stylex.defineVars({
9901
+ background: "oklch(0.145 0 0)",
9902
+ foreground: "oklch(0.985 0 0)",
9903
+ muted: "oklch(0.269 0 0)",
9904
+ mutedForeground: "oklch(0.708 0 0)",
9905
+ border: "oklch(0.469 0 0)",
9906
+ accent: "oklch(0.985 0 0)",
9907
+ accentForeground: "oklch(0.205 0 0)",
9908
+ danger: "oklch(0.637 0.237 25.331)",
9909
+ });
9910
+
9911
+ export const fonts = stylex.defineVars({
9912
+ sans: "var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif",
9913
+ mono: "var(--font-geist-mono), ui-monospace, monospace",
9914
+ });
9915
+
9916
+ export const radii = stylex.defineVars({
9917
+ sm: "6px",
9918
+ md: "8px",
9919
+ lg: "12px",
9920
+ });
9921
+ `
9922
+ },
9923
+ {
9924
+ filename: "packages/ui/src/button.tsx",
9925
+ template: `"use client";
9926
+
9927
+ import { ReactNode } from "react";
9928
+ import * as stylex from "@stylexjs/stylex";
9929
+ import type { StyleXStyles } from "@stylexjs/stylex";
9930
+ import { colors, fonts, radii } from "./tokens.stylex";
9931
+
9932
+ interface ButtonProps {
9933
+ children: ReactNode;
9934
+ onClick?: () => void;
9935
+ type?: "button" | "submit" | "reset";
9936
+ disabled?: boolean;
9937
+ style?: StyleXStyles;
9938
+ }
9939
+
9940
+ export const Button = ({ children, onClick, type = "button", disabled, style }: ButtonProps) => {
9941
+ return (
9942
+ <button
9943
+ type={type}
9944
+ onClick={onClick}
9945
+ disabled={disabled}
9946
+ {...stylex.props(styles.base, disabled && styles.disabled, style)}
9947
+ >
9948
+ {children}
9949
+ </button>
9950
+ );
9859
9951
  };
9860
- //#endregion
9861
- //#region src/templates/eslint-config/templates/base.ts
9862
- var base_default$1 = {
9863
- filename: "packages/eslint-config/base.js",
9864
- template: `import js from "@eslint/js";
9865
- import eslintConfigPrettier from "eslint-config-prettier";
9866
- import turboPlugin from "eslint-plugin-turbo";
9867
- import tseslint from "typescript-eslint";
9868
- import onlyWarn from "eslint-plugin-only-warn";
9869
9952
 
9870
- /**
9871
- * A shared ESLint configuration for the repository.
9872
- *
9873
- * @type {import("eslint").Linter.Config[]}
9874
- * */
9875
- export const config = [
9876
- js.configs.recommended,
9877
- eslintConfigPrettier,
9878
- ...tseslint.configs.recommended,
9879
- {
9880
- plugins: {
9881
- turbo: turboPlugin,
9882
- },
9883
- rules: {
9884
- "turbo/no-undeclared-env-vars": "warn",
9953
+ const styles = stylex.create({
9954
+ base: {
9955
+ display: "inline-flex",
9956
+ alignItems: "center",
9957
+ justifyContent: "center",
9958
+ gap: 8,
9959
+ height: 36,
9960
+ paddingBlock: 0,
9961
+ paddingInline: 16,
9962
+ fontFamily: fonts.sans,
9963
+ fontSize: 14,
9964
+ fontWeight: 500,
9965
+ whiteSpace: "nowrap",
9966
+ color: colors.accentForeground,
9967
+ backgroundColor: {
9968
+ default: colors.accent,
9969
+ ":hover": "oklch(0.922 0 0)",
9885
9970
  },
9886
- },
9887
- {
9888
- plugins: {
9889
- onlyWarn,
9971
+ borderStyle: "none",
9972
+ borderRadius: radii.sm,
9973
+ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.3)",
9974
+ cursor: "pointer",
9975
+ transitionProperty: "background-color",
9976
+ transitionDuration: "150ms",
9977
+ outlineColor: "rgba(255, 255, 255, 0.5)",
9978
+ outlineOffset: 2,
9979
+ outlineStyle: {
9980
+ default: "none",
9981
+ ":focus-visible": "solid",
9890
9982
  },
9983
+ outlineWidth: 2,
9891
9984
  },
9892
- {
9893
- ignores: ["dist/**"],
9985
+ disabled: {
9986
+ opacity: 0.5,
9987
+ pointerEvents: "none",
9894
9988
  },
9895
- ];`
9896
- };
9897
- //#endregion
9898
- //#region src/templates/eslint-config/templates/next.ts
9899
- var next_default = {
9900
- filename: "packages/eslint-config/next.js",
9901
- template: `import js from "@eslint/js";
9902
- import { globalIgnores } from "eslint/config";
9903
- import eslintConfigPrettier from "eslint-config-prettier";
9904
- import tseslint from "typescript-eslint";
9905
- import pluginReactHooks from "eslint-plugin-react-hooks";
9906
- import pluginReact from "eslint-plugin-react";
9907
- import globals from "globals";
9908
- import pluginNext from "@next/eslint-plugin-next";
9909
- import { config as baseConfig } from "./base.js";
9989
+ });
9990
+ `
9991
+ },
9992
+ {
9993
+ filename: "packages/ui/src/link.tsx",
9994
+ template: `import NextLink, { type LinkProps } from "next/link";
9995
+ import { type PropsWithChildren } from "react";
9996
+ import * as stylex from "@stylexjs/stylex";
9997
+ import type { StyleXStyles } from "@stylexjs/stylex";
9998
+ import { colors } from "./tokens.stylex";
9910
9999
 
9911
- /**
9912
- * A custom ESLint configuration for libraries that use Next.js.
9913
- *
9914
- * @type {import("eslint").Linter.Config[]}
9915
- * */
9916
- export const nextJsConfig = [
9917
- ...baseConfig,
9918
- js.configs.recommended,
9919
- eslintConfigPrettier,
9920
- ...tseslint.configs.recommended,
9921
- globalIgnores([
9922
- // Default ignores of eslint-config-next:
9923
- ".next/**",
9924
- "out/**",
9925
- "build/**",
9926
- "next-env.d.ts",
9927
- ]),
9928
- {
9929
- ...pluginReact.configs.flat.recommended,
9930
- languageOptions: {
9931
- ...pluginReact.configs.flat.recommended.languageOptions,
9932
- globals: {
9933
- ...globals.serviceworker,
9934
- ...globals.node,
9935
- },
9936
- },
9937
- },
9938
- {
9939
- plugins: {
9940
- "@next/next": pluginNext,
9941
- },
9942
- rules: {
9943
- ...pluginNext.configs.recommended.rules,
9944
- ...pluginNext.configs["core-web-vitals"].rules,
9945
- },
9946
- },
9947
- {
9948
- plugins: {
9949
- "react-hooks": pluginReactHooks,
9950
- },
9951
- settings: { react: { version: "detect" } },
9952
- rules: {
9953
- ...pluginReactHooks.configs.recommended.rules,
9954
- // React scope no longer necessary with new JSX transform.
9955
- "react/react-in-jsx-scope": "off",
10000
+ export function Link({
10001
+ href,
10002
+ children,
10003
+ style,
10004
+ ...rest
10005
+ }: PropsWithChildren<LinkProps & { style?: StyleXStyles }>) {
10006
+ return (
10007
+ <NextLink href={href} {...rest} {...stylex.props(styles.link, style)}>
10008
+ {children}
10009
+ </NextLink>
10010
+ );
10011
+ }
10012
+
10013
+ const styles = stylex.create({
10014
+ link: {
10015
+ color: "inherit",
10016
+ textDecorationLine: "underline",
10017
+ textDecorationColor: {
10018
+ default: colors.mutedForeground,
10019
+ ":hover": colors.foreground,
9956
10020
  },
10021
+ transitionProperty: "text-decoration-color",
10022
+ transitionDuration: "150ms",
9957
10023
  },
9958
- ];`
9959
- };
9960
- //#endregion
9961
- //#region src/templates/eslint-config/templates/react-internal.ts
9962
- var react_internal_default = {
9963
- filename: "packages/eslint-config/react-internal.js",
9964
- template: `import js from "@eslint/js";
9965
- import eslintConfigPrettier from "eslint-config-prettier";
9966
- import tseslint from "typescript-eslint";
9967
- import pluginReactHooks from "eslint-plugin-react-hooks";
9968
- import pluginReact from "eslint-plugin-react";
9969
- import globals from "globals";
9970
- import { config as baseConfig } from "./base.js";
10024
+ });
10025
+ `
10026
+ },
10027
+ {
10028
+ filename: "packages/ui/src/logo.tsx",
10029
+ template: `import * as stylex from "@stylexjs/stylex";
10030
+ import type { StyleXStyles } from "@stylexjs/stylex";
10031
+ import { colors } from "./tokens.stylex";
9971
10032
 
9972
- /**
9973
- * A custom ESLint configuration for libraries that use React.
9974
- *
9975
- * @type {import("eslint").Linter.Config[]} */
9976
- export const config = [
9977
- ...baseConfig,
9978
- js.configs.recommended,
9979
- eslintConfigPrettier,
10033
+ interface LogoProps {
10034
+ style?: StyleXStyles;
10035
+ }
10036
+
10037
+ export function Logo({ style }: LogoProps) {
10038
+ return (
10039
+ <svg
10040
+ width="196"
10041
+ height="138"
10042
+ viewBox="0 0 196 138"
10043
+ fill="none"
10044
+ xmlns="http://www.w3.org/2000/svg"
10045
+ {...stylex.props(styles.logo, style)}
10046
+ >
10047
+ <path
10048
+ d="M98 35C102.665 35 107.243 35.2232 111.707 35.6514C111.243 38.1972 111 40.8202 111 43.5C111 67.5244 130.476 87 154.5 87C165.156 87 174.914 83.1658 182.478 76.8057C183.476 79.9455 184 83.186 184 86.5C184 114.943 145.496 138 98 138C50.5035 138 12 114.943 12 86.5C12 83.1861 12.5228 79.9454 13.5215 76.8057C21.0851 83.1661 30.8441 87 41.5 87C65.5244 87 85 67.5244 85 43.5C85 40.8202 84.7559 38.1973 84.292 35.6514C88.7559 35.2232 93.3345 35 98 35ZM38.5 0C59.763 0 77 17.237 77 38.5C77 59.763 59.763 77 38.5 77C17.237 77 0 59.763 0 38.5C0 17.237 17.237 0 38.5 0ZM157.5 0C178.763 0 196 17.237 196 38.5C196 59.763 178.763 77 157.5 77C136.237 77 119 59.763 119 38.5C119 17.237 136.237 0 157.5 0Z"
10049
+ fill="currentColor"
10050
+ />
10051
+ </svg>
10052
+ );
10053
+ }
10054
+
10055
+ const styles = stylex.create({
10056
+ logo: {
10057
+ color: colors.foreground,
10058
+ },
10059
+ });
10060
+ `
10061
+ },
10062
+ {
10063
+ filename: "packages/ui/src/globals.css",
10064
+ template: `@layer resets {
10065
+ *,
10066
+ *::before,
10067
+ *::after {
10068
+ box-sizing: border-box;
10069
+ }
10070
+
10071
+ * {
10072
+ margin: 0;
10073
+ padding: 0;
10074
+ }
10075
+
10076
+ html,
10077
+ body {
10078
+ height: 100%;
10079
+ }
10080
+
10081
+ html {
10082
+ -webkit-font-smoothing: antialiased;
10083
+ -moz-osx-font-smoothing: grayscale;
10084
+ }
10085
+ }
10086
+
10087
+ @stylex;
10088
+ `
10089
+ },
10090
+ tsconfig_default$1,
10091
+ {
10092
+ when: (s) => s.nest !== "di-only",
10093
+ filename: "apps/web/package.json",
10094
+ template: `{
10095
+ "name": "web",
10096
+ "version": "0.1.0",
10097
+ "type": "module",
10098
+ "private": true,
10099
+ "scripts": {
10100
+ "dev": "next dev --port 3000",
10101
+ "build": "next build",
10102
+ "start": "next start",
10103
+ "typecheck": "next typegen && tsc --noEmit"
10104
+ },
10105
+ "dependencies": {
10106
+ "@<%= projectName %>/auth": "workspace:*",
10107
+ "@<%= projectName %>/ui": "workspace:*",
10108
+ "@stylexjs/stylex": "<%= versions["@stylexjs/stylex"] %>",
10109
+ "dotenv": "<%= versions.dotenv %>",
10110
+ "@tanstack/react-form": "<%= versions["@tanstack/react-form"] %>",
10111
+ "@tanstack/react-query": "<%= versions["@tanstack/react-query"] %>",
10112
+ "better-auth": "<%= versions["better-auth"] %>",
10113
+ "next": "<%= versions.next %>",
10114
+ "react": "<%= versions.react %>",
10115
+ "react-dom": "<%= versions["react-dom"] %>"
10116
+ },
10117
+ "devDependencies": {
10118
+ "@<%= projectName %>/typescript-config": "workspace:*",
10119
+ "@stylexjs/babel-plugin": "<%= versions["@stylexjs/babel-plugin"] %>",
10120
+ "@stylexjs/postcss-plugin": "<%= versions["@stylexjs/postcss-plugin"] %>",
10121
+ "@types/node": "<%= versions["@types/node"] %>",
10122
+ "@types/react": "<%= versions["@types/react"] %>",
10123
+ "@types/react-dom": "<%= versions["@types/react-dom"] %>",
10124
+ "typescript": "<%= versions.typescript %>"
10125
+ }
10126
+ }`
10127
+ },
10128
+ {
10129
+ when: (s) => s.nest === "di-only",
10130
+ filename: "apps/web/package.json",
10131
+ template: `{
10132
+ "name": "web",
10133
+ "version": "0.1.0",
10134
+ "type": "module",
10135
+ "private": true,
10136
+ "scripts": {
10137
+ "dev": "next dev --port 3000",
10138
+ "build": "next build",
10139
+ "start": "next start"
10140
+ },
10141
+ "dependencies": {
10142
+ "@<%= projectName %>/api": "workspace:*",
10143
+ "@<%= projectName %>/auth": "workspace:*",
10144
+ "@<%= projectName %>/db": "workspace:*",
10145
+ "@<%= projectName %>/ui": "workspace:*",
10146
+ "@nestjs/common": "<%= versions["@nestjs/common"] %>",
10147
+ "@nestjs/core": "<%= versions["@nestjs/core"] %>",
10148
+ "reflect-metadata": "<%= versions["reflect-metadata"] %>",
10149
+ "@stylexjs/stylex": "<%= versions["@stylexjs/stylex"] %>",
10150
+ "dotenv": "<%= versions.dotenv %>",
10151
+ "@tanstack/react-form": "<%= versions["@tanstack/react-form"] %>",
10152
+ "@tanstack/react-query": "<%= versions["@tanstack/react-query"] %>",
10153
+ "better-auth": "<%= versions["better-auth"] %>",
10154
+ "next": "<%= versions.next %>",
10155
+ "react": "<%= versions.react %>",
10156
+ "react-dom": "<%= versions["react-dom"] %>"
10157
+ },
10158
+ "devDependencies": {
10159
+ "@<%= projectName %>/typescript-config": "workspace:*",
10160
+ "@babel/plugin-proposal-decorators": "<%= versions["@babel/plugin-proposal-decorators"] %>",
10161
+ "@babel/plugin-transform-class-properties": "<%= versions["@babel/plugin-transform-class-properties"] %>",
10162
+ "babel-plugin-transform-typescript-metadata": "<%= versions["babel-plugin-transform-typescript-metadata"] %>",
10163
+ "@stylexjs/babel-plugin": "<%= versions["@stylexjs/babel-plugin"] %>",
10164
+ "@stylexjs/postcss-plugin": "<%= versions["@stylexjs/postcss-plugin"] %>",
10165
+ "@types/node": "<%= versions["@types/node"] %>",
10166
+ "@types/react": "<%= versions["@types/react"] %>",
10167
+ "@types/react-dom": "<%= versions["@types/react-dom"] %>",
10168
+ "typescript": "<%= versions.typescript %>"
10169
+ }
10170
+ }`
10171
+ },
10172
+ {
10173
+ filename: "apps/web/babel.config.js",
10174
+ template: `import path from "node:path";
10175
+ import { fileURLToPath } from "node:url";
10176
+
10177
+ const dirname = path.dirname(fileURLToPath(import.meta.url));
10178
+
10179
+ const config = {
10180
+ presets: ["next/babel"],
10181
+ plugins: [
10182
+ <% if (nest === 'di-only') { %> "babel-plugin-transform-typescript-metadata",
10183
+ ["@babel/plugin-proposal-decorators", { version: "legacy" }],
10184
+ ["@babel/plugin-transform-class-properties", { loose: true }],
10185
+ <% } %> [
10186
+ "@stylexjs/babel-plugin",
10187
+ {
10188
+ dev: process.env.NODE_ENV !== "production",
10189
+ runtimeInjection: false,
10190
+ treeshakeCompensation: true,
10191
+ unstable_moduleResolution: {
10192
+ type: "commonJS",
10193
+ rootDir: path.join(dirname, "../.."),
10194
+ },
10195
+ },
10196
+ ],
10197
+ ],
10198
+ };
10199
+
10200
+ export default config;`
10201
+ },
10202
+ {
10203
+ filename: "apps/web/postcss.config.mjs",
10204
+ template: `import babelConfig from "./babel.config.js";
10205
+
10206
+ const config = {
10207
+ plugins: {
10208
+ "@stylexjs/postcss-plugin": {
10209
+ include: [
10210
+ "app/**/*.{js,jsx,ts,tsx}",
10211
+ "../../packages/ui/src/**/*.{js,jsx,ts,tsx}",
10212
+ ],
10213
+ babelConfig: {
10214
+ babelrc: false,
10215
+ parserOpts: { plugins: ["typescript", "jsx"] },
10216
+ plugins: babelConfig.plugins,
10217
+ },
10218
+ useCSSLayers: true,
10219
+ },
10220
+ },
10221
+ };
10222
+
10223
+ export default config;`
10224
+ },
10225
+ {
10226
+ filename: "apps/web/app/layout.tsx",
10227
+ template: `import type { Metadata } from "next";
10228
+ import localFont from "next/font/local";
10229
+ import * as stylex from "@stylexjs/stylex";
10230
+ import Providers from "@/app/providers";
10231
+ import { colors, fonts } from "@<%= projectName %>/ui/tokens.stylex";
10232
+ import "@<%= projectName %>/ui/globals.css";
10233
+
10234
+ const geistSans = localFont({
10235
+ src: "./fonts/GeistVF.woff",
10236
+ variable: "--font-geist-sans",
10237
+ });
10238
+ const geistMono = localFont({
10239
+ src: "./fonts/GeistMonoVF.woff",
10240
+ variable: "--font-geist-mono",
10241
+ });
10242
+
10243
+ export const metadata: Metadata = {
10244
+ title: "<%= projectName %>",
10245
+ description: "Next + Nest = Newt",
10246
+ icons: {
10247
+ icon: [
10248
+ { url: "/icon0.svg", type: "image/svg+xml" },
10249
+ { url: "/icon1.png", type: "image/png" },
10250
+ ],
10251
+ apple: "/apple-icon.png",
10252
+ },
10253
+ };
10254
+
10255
+ export default function RootLayout({
10256
+ children,
10257
+ }: Readonly<{
10258
+ children: React.ReactNode;
10259
+ }>) {
10260
+ return (
10261
+ <html lang="en" className={\`\${geistSans.variable} \${geistMono.variable}\`}>
10262
+ <body {...stylex.props(styles.body)}>
10263
+ <Providers>{children}</Providers>
10264
+ </body>
10265
+ </html>
10266
+ );
10267
+ }
10268
+
10269
+ const styles = stylex.create({
10270
+ body: {
10271
+ backgroundColor: colors.background,
10272
+ color: colors.foreground,
10273
+ fontFamily: fonts.sans,
10274
+ },
10275
+ });
10276
+ `
10277
+ },
10278
+ {
10279
+ when: (s) => !s.todoExample,
10280
+ filename: "apps/web/app/page.tsx",
10281
+ template: `'use client';
10282
+
10283
+ import { useQuery } from '@tanstack/react-query';
10284
+ import * as stylex from '@stylexjs/stylex';
10285
+ import { authClient } from '@/lib/auth-client';
10286
+ import { AuthForm } from '@/app/auth-form';
10287
+ import { Button } from '@<%= projectName %>/ui/button';
10288
+ import { Link } from '@<%= projectName %>/ui/link';
10289
+ import { Logo } from '@<%= projectName %>/ui/logo';
10290
+ import { colors, fonts, radii } from '@<%= projectName %>/ui/tokens.stylex';
10291
+
10292
+ export default function Home() {
10293
+ const { data: session, isPending } = authClient.useSession();
10294
+
10295
+ const { data: hello } = useQuery({
10296
+ queryKey: ['hello'],
10297
+ queryFn: () => fetch('/api/hello').then((r) => r.json()),
10298
+ });
10299
+
10300
+ return (
10301
+ <main {...stylex.props(styles.main)}>
10302
+ <div {...stylex.props(styles.header)}>
10303
+ <p {...stylex.props(styles.mono, styles.muted)}>apps/web/app/page.tsx</p>
10304
+ <p {...stylex.props(styles.muted)}>Delete me to get started!</p>
10305
+ </div>
10306
+
10307
+ <div {...stylex.props(styles.titleRow)}>
10308
+ <Logo style={styles.logo} />
10309
+ <div>
10310
+ <h1 {...stylex.props(styles.h1)}><%= projectName %></h1>
10311
+ <p {...stylex.props(styles.muted, styles.tagline)}>
10312
+ Next + Nest = Newt 💜
10313
+ </p>
10314
+ </div>
10315
+ </div>
10316
+
10317
+ <div {...stylex.props(styles.card)}>
10318
+ <p {...stylex.props(styles.eyebrow)}>next.js</p>
10319
+ <p {...stylex.props(styles.mono, styles.muted)}>apps/web/app/layout.tsx</p>
10320
+ <p {...stylex.props(styles.muted)}>Next.js rendering</p>
10321
+ </div>
10322
+
10323
+ <div {...stylex.props(styles.card)}>
10324
+ <p {...stylex.props(styles.eyebrow)}>nest.js</p>
10325
+ <p {...stylex.props(styles.mono, styles.muted)}>GET /api/hello</p>
10326
+ <pre {...stylex.props(styles.pre)}>
10327
+ <code>{JSON.stringify(hello, null, 2)}</code>
10328
+ </pre>
10329
+ </div>
10330
+
10331
+ <div {...stylex.props(styles.card)}>
10332
+ <p {...stylex.props(styles.eyebrow, styles.eyebrowSpaced)}>better-auth</p>
10333
+ {isPending ? (
10334
+ <p {...stylex.props(styles.muted)}>Loading…</p>
10335
+ ) : session ? (
10336
+ <div {...stylex.props(styles.signedIn)}>
10337
+ <p>Signed in as {session.user.name}</p>
10338
+ <Button onClick={() => void authClient.signOut()}>
10339
+ Sign out
10340
+ </Button>
10341
+ </div>
10342
+ ) : (
10343
+ <AuthForm />
10344
+ )}
10345
+ </div>
10346
+
10347
+ <div {...stylex.props(styles.footer)}>
10348
+ <p {...stylex.props(styles.muted)}>Learn more</p>
10349
+ <ul {...stylex.props(styles.list)}>
10350
+ <li>
10351
+ <Link href="https://newt-app.com">Documentation</Link>
10352
+ </li>
10353
+ <li>
10354
+ <Link href="https://github.com/zeevo/newt-app">GitHub</Link>
10355
+ </li>
10356
+ <li>
10357
+ <Link href="https://nextjs.org">Next.js</Link>
10358
+ </li>
10359
+ <li>
10360
+ <Link href="https://nestjs.com">NestJS</Link>
10361
+ </li>
10362
+ </ul>
10363
+ </div>
10364
+ </main>
10365
+ );
10366
+ }
10367
+
10368
+ const styles = stylex.create({
10369
+ main: {
10370
+ display: 'flex',
10371
+ flexDirection: 'column',
10372
+ gap: '1rem',
10373
+ maxWidth: '32rem',
10374
+ minHeight: '100%',
10375
+ marginInline: 'auto',
10376
+ paddingBlock: '2rem',
10377
+ paddingInline: '1rem',
10378
+ fontSize: '0.875rem',
10379
+ },
10380
+ header: {
10381
+ paddingBottom: '1rem',
10382
+ borderBottomColor: colors.border,
10383
+ borderBottomStyle: 'solid',
10384
+ borderBottomWidth: 1,
10385
+ },
10386
+ titleRow: {
10387
+ display: 'flex',
10388
+ alignItems: 'center',
10389
+ gap: '0.75rem',
10390
+ paddingBlock: '0.5rem',
10391
+ },
10392
+ logo: {
10393
+ width: '2.5rem',
10394
+ height: 'auto',
10395
+ },
10396
+ h1: {
10397
+ fontSize: '2.25rem',
10398
+ fontWeight: 900,
10399
+ letterSpacing: '-0.025em',
10400
+ },
10401
+ tagline: {
10402
+ letterSpacing: '0.1em',
10403
+ textTransform: 'uppercase',
10404
+ },
10405
+ card: {
10406
+ display: 'flex',
10407
+ flexDirection: 'column',
10408
+ gap: '0.25rem',
10409
+ padding: '1.5rem',
10410
+ borderColor: colors.border,
10411
+ borderRadius: radii.lg,
10412
+ borderStyle: 'solid',
10413
+ borderWidth: 1,
10414
+ },
10415
+ eyebrow: {
10416
+ fontFamily: fonts.mono,
10417
+ fontSize: '0.75rem',
10418
+ letterSpacing: '0.1em',
10419
+ textTransform: 'uppercase',
10420
+ color: colors.mutedForeground,
10421
+ },
10422
+ eyebrowSpaced: {
10423
+ marginBottom: '0.75rem',
10424
+ },
10425
+ pre: {
10426
+ marginTop: '0.5rem',
10427
+ padding: '0.75rem',
10428
+ fontFamily: fonts.mono,
10429
+ backgroundColor: 'oklch(0.269 0 0 / 0.5)',
10430
+ borderColor: colors.border,
10431
+ borderRadius: radii.sm,
10432
+ borderStyle: 'solid',
10433
+ borderWidth: 1,
10434
+ overflowX: 'auto',
10435
+ },
10436
+ signedIn: {
10437
+ display: 'flex',
10438
+ flexDirection: 'column',
10439
+ alignItems: 'flex-start',
10440
+ gap: '0.75rem',
10441
+ },
10442
+ footer: {
10443
+ display: 'flex',
10444
+ flexDirection: 'column',
10445
+ gap: '0.5rem',
10446
+ paddingBlock: '1rem',
10447
+ paddingInline: '0.5rem',
10448
+ },
10449
+ list: {
10450
+ display: 'flex',
10451
+ flexDirection: 'column',
10452
+ gap: '0.5rem',
10453
+ listStylePosition: 'inside',
10454
+ listStyleType: 'disc',
10455
+ },
10456
+ mono: {
10457
+ fontFamily: fonts.mono,
10458
+ },
10459
+ muted: {
10460
+ color: colors.mutedForeground,
10461
+ },
10462
+ });
10463
+ `
10464
+ },
10465
+ {
10466
+ filename: "apps/web/app/auth-form.tsx",
10467
+ template: `'use client';
10468
+
10469
+ import { useForm } from '@tanstack/react-form';
10470
+ import { useState } from 'react';
10471
+ import * as stylex from '@stylexjs/stylex';
10472
+ import { authClient } from '@/lib/auth-client';
10473
+ import { Button } from '@<%= projectName %>/ui/button';
10474
+ import { colors, radii } from '@<%= projectName %>/ui/tokens.stylex';
10475
+
10476
+ export function AuthForm() {
10477
+ const [tab, setTab] = useState<'signin' | 'signup'>('signup');
10478
+ const [error, setError] = useState('');
10479
+
10480
+ const form = useForm({
10481
+ defaultValues: { name: '', email: '', password: '' },
10482
+ onSubmit: async ({ value }) => {
10483
+ setError('');
10484
+ if (tab === 'signin') {
10485
+ const { error } = await authClient.signIn.email(value);
10486
+ if (error) setError(error.message ?? 'Sign in failed');
10487
+ } else {
10488
+ const { error } = await authClient.signUp.email(value);
10489
+ if (error) setError(error.message ?? 'Sign up failed');
10490
+ }
10491
+ },
10492
+ });
10493
+
10494
+ return (
10495
+ <>
10496
+ <div {...stylex.props(styles.tabs)}>
10497
+ <button
10498
+ onClick={() => setTab('signup')}
10499
+ {...stylex.props(styles.tab, tab === 'signup' && styles.tabActive)}
10500
+ >
10501
+ Sign up
10502
+ </button>
10503
+ <span {...stylex.props(styles.divider)}>|</span>
10504
+ <button
10505
+ onClick={() => setTab('signin')}
10506
+ {...stylex.props(styles.tab, tab === 'signin' && styles.tabActive)}
10507
+ >
10508
+ Sign in
10509
+ </button>
10510
+ </div>
10511
+
10512
+ <form
10513
+ onSubmit={(e) => {
10514
+ e.preventDefault();
10515
+ form.handleSubmit();
10516
+ }}
10517
+ {...stylex.props(styles.form)}
10518
+ >
10519
+ {tab === 'signup' && (
10520
+ <form.Field name="name">
10521
+ {(field) => (
10522
+ <div {...stylex.props(styles.field)}>
10523
+ <label {...stylex.props(styles.label)}>Name</label>
10524
+ <input
10525
+ type="text"
10526
+ autoComplete="name"
10527
+ value={field.state.value}
10528
+ onChange={(e) => field.handleChange(e.target.value)}
10529
+ required
10530
+ {...stylex.props(styles.input)}
10531
+ />
10532
+ </div>
10533
+ )}
10534
+ </form.Field>
10535
+ )}
10536
+
10537
+ <form.Field name="email">
10538
+ {(field) => (
10539
+ <div {...stylex.props(styles.field)}>
10540
+ <label {...stylex.props(styles.label)}>Email</label>
10541
+ <input
10542
+ type="email"
10543
+ autoComplete="email"
10544
+ value={field.state.value}
10545
+ onChange={(e) => field.handleChange(e.target.value)}
10546
+ required
10547
+ {...stylex.props(styles.input)}
10548
+ />
10549
+ </div>
10550
+ )}
10551
+ </form.Field>
10552
+
10553
+ <form.Field name="password">
10554
+ {(field) => (
10555
+ <div {...stylex.props(styles.field)}>
10556
+ <label {...stylex.props(styles.label)}>Password</label>
10557
+ <input
10558
+ type="password"
10559
+ autoComplete={
10560
+ tab === 'signin' ? 'current-password' : 'new-password'
10561
+ }
10562
+ value={field.state.value}
10563
+ onChange={(e) => field.handleChange(e.target.value)}
10564
+ required
10565
+ minLength={8}
10566
+ {...stylex.props(styles.input)}
10567
+ />
10568
+ </div>
10569
+ )}
10570
+ </form.Field>
10571
+
10572
+ {error && <p {...stylex.props(styles.error)}>{error}</p>}
10573
+
10574
+ <form.Subscribe selector={(s) => s.isSubmitting}>
10575
+ {(isSubmitting) => (
10576
+ <Button type="submit" disabled={isSubmitting} style={styles.submit}>
10577
+ {isSubmitting
10578
+ ? 'Loading…'
10579
+ : tab === 'signin'
10580
+ ? 'Sign in'
10581
+ : 'Create account'}
10582
+ </Button>
10583
+ )}
10584
+ </form.Subscribe>
10585
+ </form>
10586
+ </>
10587
+ );
10588
+ }
10589
+
10590
+ const styles = stylex.create({
10591
+ tabs: {
10592
+ display: 'flex',
10593
+ gap: '0.5rem',
10594
+ marginBottom: '1.5rem',
10595
+ fontSize: '0.875rem',
10596
+ },
10597
+ tab: {
10598
+ color: {
10599
+ default: colors.mutedForeground,
10600
+ ':hover': colors.foreground,
10601
+ },
10602
+ backgroundColor: 'transparent',
10603
+ borderStyle: 'none',
10604
+ cursor: 'pointer',
10605
+ padding: 0,
10606
+ fontFamily: 'inherit',
10607
+ fontSize: 'inherit',
10608
+ },
10609
+ tabActive: {
10610
+ color: colors.foreground,
10611
+ fontWeight: 600,
10612
+ },
10613
+ divider: {
10614
+ color: colors.border,
10615
+ },
10616
+ form: {
10617
+ display: 'flex',
10618
+ flexDirection: 'column',
10619
+ gap: '1rem',
10620
+ },
10621
+ field: {
10622
+ display: 'flex',
10623
+ flexDirection: 'column',
10624
+ gap: '0.25rem',
10625
+ },
10626
+ label: {
10627
+ fontSize: '0.875rem',
10628
+ fontWeight: 500,
10629
+ },
10630
+ input: {
10631
+ width: '100%',
10632
+ height: 36,
10633
+ paddingBlock: '0.25rem',
10634
+ paddingInline: '0.75rem',
10635
+ fontFamily: 'inherit',
10636
+ fontSize: '0.875rem',
10637
+ color: colors.foreground,
10638
+ backgroundColor: 'oklch(0.269 0 0 / 0.5)',
10639
+ borderColor: {
10640
+ default: colors.border,
10641
+ ':focus-visible': colors.mutedForeground,
10642
+ },
10643
+ borderRadius: radii.sm,
10644
+ borderStyle: 'solid',
10645
+ borderWidth: 1,
10646
+ outlineStyle: 'none',
10647
+ transitionProperty: 'border-color',
10648
+ transitionDuration: '150ms',
10649
+ },
10650
+ error: {
10651
+ fontSize: '0.875rem',
10652
+ color: colors.danger,
10653
+ },
10654
+ submit: {
10655
+ width: '100%',
10656
+ },
10657
+ });
10658
+ `
10659
+ }
10660
+ ] };
10661
+ //#endregion
10662
+ //#region src/templates/eslint-config/templates/package-json.ts
10663
+ var package_json_default$1 = {
10664
+ filename: "packages/eslint-config/package.json",
10665
+ template: `{
10666
+ "name": "@<%= projectName %>/eslint-config",
10667
+ "version": "0.0.0",
10668
+ "type": "module",
10669
+ "private": true,
10670
+ "exports": {
10671
+ "./base": "./base.js",
10672
+ "./next-js": "./next.js",
10673
+ "./react-internal": "./react-internal.js"
10674
+ },
10675
+ "devDependencies": {
10676
+ "@eslint/js": "<%= versions["@eslint/js"] %>",
10677
+ "@next/eslint-plugin-next": "<%= versions["@next/eslint-plugin-next"] %>",
10678
+ "eslint": "<%= versions.eslint %>",
10679
+ "eslint-config-prettier": "<%= versions["eslint-config-prettier"] %>",
10680
+ "eslint-plugin-only-warn": "<%= versions["eslint-plugin-only-warn"] %>",
10681
+ "eslint-plugin-react": "<%= versions["eslint-plugin-react"] %>",
10682
+ "eslint-plugin-react-hooks": "<%= versions["eslint-plugin-react-hooks"] %>",
10683
+ "eslint-plugin-turbo": "<%= versions["eslint-plugin-turbo"] %>",
10684
+ "globals": "<%= versions.globals %>",
10685
+ "typescript": "<%= versions.typescript %>",
10686
+ "typescript-eslint": "<%= versions["typescript-eslint"] %>"
10687
+ }
10688
+ }`
10689
+ };
10690
+ //#endregion
10691
+ //#region src/templates/eslint-config/templates/base.ts
10692
+ var base_default$1 = {
10693
+ filename: "packages/eslint-config/base.js",
10694
+ template: `import js from "@eslint/js";
10695
+ import eslintConfigPrettier from "eslint-config-prettier";
10696
+ import turboPlugin from "eslint-plugin-turbo";
10697
+ import tseslint from "typescript-eslint";
10698
+ import onlyWarn from "eslint-plugin-only-warn";
10699
+
10700
+ /**
10701
+ * A shared ESLint configuration for the repository.
10702
+ *
10703
+ * @type {import("eslint").Linter.Config[]}
10704
+ * */
10705
+ export const config = [
10706
+ js.configs.recommended,
10707
+ eslintConfigPrettier,
10708
+ ...tseslint.configs.recommended,
10709
+ {
10710
+ plugins: {
10711
+ turbo: turboPlugin,
10712
+ },
10713
+ rules: {
10714
+ "turbo/no-undeclared-env-vars": "warn",
10715
+ },
10716
+ },
10717
+ {
10718
+ plugins: {
10719
+ onlyWarn,
10720
+ },
10721
+ },
10722
+ {
10723
+ ignores: ["dist/**"],
10724
+ },
10725
+ ];`
10726
+ };
10727
+ //#endregion
10728
+ //#region src/templates/eslint-config/templates/next.ts
10729
+ var next_default = {
10730
+ filename: "packages/eslint-config/next.js",
10731
+ template: `import js from "@eslint/js";
10732
+ import { globalIgnores } from "eslint/config";
10733
+ import eslintConfigPrettier from "eslint-config-prettier";
10734
+ import tseslint from "typescript-eslint";
10735
+ import pluginReactHooks from "eslint-plugin-react-hooks";
10736
+ import pluginReact from "eslint-plugin-react";
10737
+ import globals from "globals";
10738
+ import pluginNext from "@next/eslint-plugin-next";
10739
+ import { config as baseConfig } from "./base.js";
10740
+
10741
+ /**
10742
+ * A custom ESLint configuration for libraries that use Next.js.
10743
+ *
10744
+ * @type {import("eslint").Linter.Config[]}
10745
+ * */
10746
+ export const nextJsConfig = [
10747
+ ...baseConfig,
10748
+ js.configs.recommended,
10749
+ eslintConfigPrettier,
10750
+ ...tseslint.configs.recommended,
10751
+ globalIgnores([
10752
+ // Default ignores of eslint-config-next:
10753
+ ".next/**",
10754
+ "out/**",
10755
+ "build/**",
10756
+ "next-env.d.ts",
10757
+ ]),
10758
+ {
10759
+ ...pluginReact.configs.flat.recommended,
10760
+ languageOptions: {
10761
+ ...pluginReact.configs.flat.recommended.languageOptions,
10762
+ globals: {
10763
+ ...globals.serviceworker,
10764
+ ...globals.node,
10765
+ },
10766
+ },
10767
+ },
10768
+ {
10769
+ plugins: {
10770
+ "@next/next": pluginNext,
10771
+ },
10772
+ rules: {
10773
+ ...pluginNext.configs.recommended.rules,
10774
+ ...pluginNext.configs["core-web-vitals"].rules,
10775
+ },
10776
+ },
10777
+ {
10778
+ plugins: {
10779
+ "react-hooks": pluginReactHooks,
10780
+ },
10781
+ settings: { react: { version: "detect" } },
10782
+ rules: {
10783
+ ...pluginReactHooks.configs.recommended.rules,
10784
+ // React scope no longer necessary with new JSX transform.
10785
+ "react/react-in-jsx-scope": "off",
10786
+ },
10787
+ },
10788
+ ];`
10789
+ };
10790
+ //#endregion
10791
+ //#region src/templates/eslint-config/templates/react-internal.ts
10792
+ var react_internal_default = {
10793
+ filename: "packages/eslint-config/react-internal.js",
10794
+ template: `import js from "@eslint/js";
10795
+ import eslintConfigPrettier from "eslint-config-prettier";
10796
+ import tseslint from "typescript-eslint";
10797
+ import pluginReactHooks from "eslint-plugin-react-hooks";
10798
+ import pluginReact from "eslint-plugin-react";
10799
+ import globals from "globals";
10800
+ import { config as baseConfig } from "./base.js";
10801
+
10802
+ /**
10803
+ * A custom ESLint configuration for libraries that use React.
10804
+ *
10805
+ * @type {import("eslint").Linter.Config[]} */
10806
+ export const config = [
10807
+ ...baseConfig,
10808
+ js.configs.recommended,
10809
+ eslintConfigPrettier,
9980
10810
  ...tseslint.configs.recommended,
9981
10811
  pluginReact.configs.flat.recommended,
9982
10812
  {
@@ -11095,6 +11925,7 @@ export async function GET() {
11095
11925
  }`
11096
11926
  },
11097
11927
  {
11928
+ when: (s) => !s.stylex,
11098
11929
  filename: "apps/web/package.json",
11099
11930
  template: `{
11100
11931
  "name": "web",
@@ -11968,7 +12799,7 @@ export function TodoList({
11968
12799
  //#endregion
11969
12800
  //#region src/templates/todo-example/templates/web-page.ts
11970
12801
  var web_page_default = {
11971
- when: (s) => s.todoExample && !s.shadcn,
12802
+ when: (s) => s.todoExample && !s.shadcn && !s.stylex,
11972
12803
  filename: "apps/web/app/page.tsx",
11973
12804
  template: `'use client';
11974
12805
 
@@ -12306,6 +13137,424 @@ export default function Home() {
12306
13137
  }`
12307
13138
  };
12308
13139
  //#endregion
13140
+ //#region src/templates/todo-example/templates/stylex-todo-list.ts
13141
+ var stylex_todo_list_default = {
13142
+ filename: "apps/web/app/todo-list.tsx",
13143
+ template: `'use client';
13144
+
13145
+ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
13146
+ import { useForm } from '@tanstack/react-form';
13147
+ import * as stylex from '@stylexjs/stylex';
13148
+ import { authClient } from '@/lib/auth-client';
13149
+ import { Button } from '@<%= projectName %>/ui/button';
13150
+ import { colors, radii } from '@<%= projectName %>/ui/tokens.stylex';
13151
+
13152
+ interface Todo {
13153
+ id: string;
13154
+ title: string;
13155
+ done: boolean;
13156
+ }
13157
+
13158
+ const api = {
13159
+ getTodos: (): Promise<Todo[]> => fetch('/api/todos').then((r) => r.json()),
13160
+ createTodo: (title: string): Promise<Todo> =>
13161
+ fetch('/api/todos', {
13162
+ method: 'POST',
13163
+ headers: { 'Content-Type': 'application/json' },
13164
+ body: JSON.stringify({ title }),
13165
+ }).then((r) => r.json()),
13166
+ toggleTodo: (id: string): Promise<Todo> =>
13167
+ fetch(\`/api/todos/\${id}/toggle\`, { method: 'PATCH' }).then((r) => r.json()),
13168
+ deleteTodo: (id: string): Promise<void> =>
13169
+ fetch(\`/api/todos/\${id}\`, { method: 'DELETE' }).then(() => undefined),
13170
+ };
13171
+
13172
+ export function TodoList({
13173
+ session,
13174
+ }: {
13175
+ session: { user: { email: string } };
13176
+ }) {
13177
+ const queryClient = useQueryClient();
13178
+
13179
+ const { data: todos = [], isPending } = useQuery({
13180
+ queryKey: ['todos'],
13181
+ queryFn: api.getTodos,
13182
+ });
13183
+
13184
+ const createMutation = useMutation({
13185
+ mutationFn: api.createTodo,
13186
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
13187
+ });
13188
+
13189
+ const toggleMutation = useMutation({
13190
+ mutationFn: api.toggleTodo,
13191
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
13192
+ });
13193
+
13194
+ const deleteMutation = useMutation({
13195
+ mutationFn: api.deleteTodo,
13196
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
13197
+ });
13198
+
13199
+ const form = useForm({
13200
+ defaultValues: { title: '' },
13201
+ onSubmit: async ({ value }) => {
13202
+ if (!value.title.trim()) return;
13203
+ createMutation.mutate(value.title.trim());
13204
+ form.reset();
13205
+ },
13206
+ });
13207
+
13208
+ return (
13209
+ <>
13210
+ <div {...stylex.props(styles.header)}>
13211
+ <h1 {...stylex.props(styles.h1)}>Todos</h1>
13212
+ <div {...stylex.props(styles.session)}>
13213
+ <span>{session.user.email}</span>
13214
+ <button
13215
+ {...stylex.props(styles.signOut)}
13216
+ onClick={() => authClient.signOut()}
13217
+ >
13218
+ Sign out
13219
+ </button>
13220
+ </div>
13221
+ </div>
13222
+
13223
+ <form
13224
+ onSubmit={(e) => {
13225
+ e.preventDefault();
13226
+ form.handleSubmit();
13227
+ }}
13228
+ {...stylex.props(styles.form)}
13229
+ >
13230
+ <form.Field name="title">
13231
+ {(field) => (
13232
+ <input
13233
+ value={field.state.value}
13234
+ onChange={(e) => field.handleChange(e.target.value)}
13235
+ placeholder="New todo…"
13236
+ {...stylex.props(styles.input)}
13237
+ />
13238
+ )}
13239
+ </form.Field>
13240
+
13241
+ <form.Subscribe selector={(s) => s.isSubmitting}>
13242
+ {(isSubmitting) => (
13243
+ <Button type="submit" disabled={isSubmitting || createMutation.isPending}>
13244
+ Add
13245
+ </Button>
13246
+ )}
13247
+ </form.Subscribe>
13248
+ </form>
13249
+
13250
+ {isPending ? (
13251
+ <p {...stylex.props(styles.muted)}>Loading…</p>
13252
+ ) : (
13253
+ <ul {...stylex.props(styles.list)}>
13254
+ {todos.map((todo) => (
13255
+ <li key={todo.id} {...stylex.props(styles.item)}>
13256
+ <input
13257
+ type="checkbox"
13258
+ checked={todo.done}
13259
+ onChange={() => toggleMutation.mutate(todo.id)}
13260
+ />
13261
+ <span {...stylex.props(styles.title, todo.done && styles.titleDone)}>
13262
+ {todo.title}
13263
+ </span>
13264
+ <button
13265
+ onClick={() => deleteMutation.mutate(todo.id)}
13266
+ {...stylex.props(styles.remove)}
13267
+ >
13268
+ ×
13269
+ </button>
13270
+ </li>
13271
+ ))}
13272
+ </ul>
13273
+ )}
13274
+
13275
+ {!isPending && todos.length === 0 && (
13276
+ <p {...stylex.props(styles.muted)}>No todos yet.</p>
13277
+ )}
13278
+ </>
13279
+ );
13280
+ }
13281
+
13282
+ const styles = stylex.create({
13283
+ header: {
13284
+ display: 'flex',
13285
+ alignItems: 'center',
13286
+ justifyContent: 'space-between',
13287
+ marginBottom: '2rem',
13288
+ },
13289
+ h1: {
13290
+ fontSize: '1.5rem',
13291
+ fontWeight: 600,
13292
+ },
13293
+ session: {
13294
+ display: 'flex',
13295
+ alignItems: 'center',
13296
+ gap: '0.75rem',
13297
+ fontSize: '0.875rem',
13298
+ color: colors.mutedForeground,
13299
+ },
13300
+ signOut: {
13301
+ color: {
13302
+ default: 'inherit',
13303
+ ':hover': colors.foreground,
13304
+ },
13305
+ backgroundColor: 'transparent',
13306
+ borderStyle: 'none',
13307
+ cursor: 'pointer',
13308
+ padding: 0,
13309
+ fontFamily: 'inherit',
13310
+ fontSize: 'inherit',
13311
+ },
13312
+ form: {
13313
+ display: 'flex',
13314
+ gap: '0.5rem',
13315
+ marginBottom: '1.5rem',
13316
+ },
13317
+ input: {
13318
+ flexGrow: 1,
13319
+ height: 36,
13320
+ paddingBlock: '0.25rem',
13321
+ paddingInline: '0.75rem',
13322
+ fontFamily: 'inherit',
13323
+ fontSize: '0.875rem',
13324
+ color: colors.foreground,
13325
+ backgroundColor: 'oklch(0.269 0 0 / 0.5)',
13326
+ borderColor: {
13327
+ default: colors.border,
13328
+ ':focus-visible': colors.mutedForeground,
13329
+ },
13330
+ borderRadius: radii.sm,
13331
+ borderStyle: 'solid',
13332
+ borderWidth: 1,
13333
+ outlineStyle: 'none',
13334
+ transitionProperty: 'border-color',
13335
+ transitionDuration: '150ms',
13336
+ },
13337
+ list: {
13338
+ listStyleType: 'none',
13339
+ },
13340
+ item: {
13341
+ display: 'flex',
13342
+ alignItems: 'center',
13343
+ gap: '0.75rem',
13344
+ paddingBlock: '0.75rem',
13345
+ borderTopColor: colors.border,
13346
+ borderTopStyle: 'solid',
13347
+ borderTopWidth: {
13348
+ default: 1,
13349
+ ':first-child': 0,
13350
+ },
13351
+ },
13352
+ title: {
13353
+ flexGrow: 1,
13354
+ fontSize: '0.875rem',
13355
+ },
13356
+ titleDone: {
13357
+ color: colors.mutedForeground,
13358
+ textDecorationLine: 'line-through',
13359
+ },
13360
+ remove: {
13361
+ color: {
13362
+ default: colors.mutedForeground,
13363
+ ':hover': colors.danger,
13364
+ },
13365
+ backgroundColor: 'transparent',
13366
+ borderStyle: 'none',
13367
+ cursor: 'pointer',
13368
+ padding: 0,
13369
+ fontSize: '1.125rem',
13370
+ lineHeight: 1,
13371
+ },
13372
+ muted: {
13373
+ fontSize: '0.875rem',
13374
+ color: colors.mutedForeground,
13375
+ },
13376
+ });
13377
+ `
13378
+ };
13379
+ //#endregion
13380
+ //#region src/templates/todo-example/templates/stylex-page.ts
13381
+ var stylex_page_default = {
13382
+ when: (s) => s.todoExample && s.stylex,
13383
+ filename: "apps/web/app/page.tsx",
13384
+ template: `'use client';
13385
+
13386
+ import { useQuery } from '@tanstack/react-query';
13387
+ import * as stylex from '@stylexjs/stylex';
13388
+ import { authClient } from '@/lib/auth-client';
13389
+ import { AuthForm } from '@/app/auth-form';
13390
+ import { Link } from '@<%= projectName %>/ui/link';
13391
+ import { Logo } from '@<%= projectName %>/ui/logo';
13392
+ import { TodoList } from '@/app/todo-list';
13393
+ import { colors, fonts, radii } from '@<%= projectName %>/ui/tokens.stylex';
13394
+
13395
+ export default function Home() {
13396
+ const { data: session, isPending } = authClient.useSession();
13397
+
13398
+ const { data: hello } = useQuery({
13399
+ queryKey: ['hello'],
13400
+ queryFn: () => fetch('/api/hello').then((r) => r.json()),
13401
+ });
13402
+
13403
+ return (
13404
+ <main {...stylex.props(styles.main)}>
13405
+ <div {...stylex.props(styles.header)}>
13406
+ <p {...stylex.props(styles.mono, styles.muted)}>apps/web/app/page.tsx</p>
13407
+ <p {...stylex.props(styles.muted)}>Delete me to get started!</p>
13408
+ </div>
13409
+
13410
+ <div {...stylex.props(styles.titleRow)}>
13411
+ <Logo style={styles.logo} />
13412
+ <div>
13413
+ <h1 {...stylex.props(styles.h1)}><%= projectName %></h1>
13414
+ <p {...stylex.props(styles.muted, styles.tagline)}>
13415
+ Next + Nest = Newt 💜
13416
+ </p>
13417
+ </div>
13418
+ </div>
13419
+
13420
+ <div {...stylex.props(styles.card)}>
13421
+ <p {...stylex.props(styles.eyebrow)}>next.js</p>
13422
+ <p {...stylex.props(styles.mono, styles.muted)}>apps/web/app/layout.tsx</p>
13423
+ <p {...stylex.props(styles.muted)}>Next.js rendering</p>
13424
+ </div>
13425
+
13426
+ <div {...stylex.props(styles.card)}>
13427
+ <p {...stylex.props(styles.eyebrow)}>nest.js</p>
13428
+ <p {...stylex.props(styles.mono, styles.muted)}>GET /api/hello</p>
13429
+ <pre {...stylex.props(styles.pre)}>
13430
+ <code>{JSON.stringify(hello, null, 2)}</code>
13431
+ </pre>
13432
+ </div>
13433
+
13434
+ <div {...stylex.props(styles.card)}>
13435
+ <p {...stylex.props(styles.eyebrow, styles.eyebrowSpaced)}>better-auth</p>
13436
+ {isPending ? (
13437
+ <p {...stylex.props(styles.muted)}>Loading…</p>
13438
+ ) : session ? (
13439
+ <TodoList session={session} />
13440
+ ) : (
13441
+ <AuthForm />
13442
+ )}
13443
+ </div>
13444
+
13445
+ <div {...stylex.props(styles.footer)}>
13446
+ <p {...stylex.props(styles.muted)}>Learn more</p>
13447
+ <ul {...stylex.props(styles.list)}>
13448
+ <li>
13449
+ <Link href="https://newt-app.com">Documentation</Link>
13450
+ </li>
13451
+ <li>
13452
+ <Link href="https://github.com/zeevo/newt-app">GitHub</Link>
13453
+ </li>
13454
+ <li>
13455
+ <Link href="https://nextjs.org">Next.js</Link>
13456
+ </li>
13457
+ <li>
13458
+ <Link href="https://nestjs.com">NestJS</Link>
13459
+ </li>
13460
+ </ul>
13461
+ </div>
13462
+ </main>
13463
+ );
13464
+ }
13465
+
13466
+ const styles = stylex.create({
13467
+ main: {
13468
+ display: 'flex',
13469
+ flexDirection: 'column',
13470
+ gap: '1rem',
13471
+ maxWidth: '32rem',
13472
+ minHeight: '100%',
13473
+ marginInline: 'auto',
13474
+ paddingBlock: '2rem',
13475
+ paddingInline: '1rem',
13476
+ fontSize: '0.875rem',
13477
+ },
13478
+ header: {
13479
+ paddingBottom: '1rem',
13480
+ borderBottomColor: colors.border,
13481
+ borderBottomStyle: 'solid',
13482
+ borderBottomWidth: 1,
13483
+ },
13484
+ titleRow: {
13485
+ display: 'flex',
13486
+ alignItems: 'center',
13487
+ gap: '0.75rem',
13488
+ paddingBlock: '0.5rem',
13489
+ },
13490
+ logo: {
13491
+ width: '2.5rem',
13492
+ height: 'auto',
13493
+ },
13494
+ h1: {
13495
+ fontSize: '2.25rem',
13496
+ fontWeight: 900,
13497
+ letterSpacing: '-0.025em',
13498
+ },
13499
+ tagline: {
13500
+ letterSpacing: '0.1em',
13501
+ textTransform: 'uppercase',
13502
+ },
13503
+ card: {
13504
+ display: 'flex',
13505
+ flexDirection: 'column',
13506
+ gap: '0.25rem',
13507
+ padding: '1.5rem',
13508
+ borderColor: colors.border,
13509
+ borderRadius: radii.lg,
13510
+ borderStyle: 'solid',
13511
+ borderWidth: 1,
13512
+ },
13513
+ eyebrow: {
13514
+ fontFamily: fonts.mono,
13515
+ fontSize: '0.75rem',
13516
+ letterSpacing: '0.1em',
13517
+ textTransform: 'uppercase',
13518
+ color: colors.mutedForeground,
13519
+ },
13520
+ eyebrowSpaced: {
13521
+ marginBottom: '0.75rem',
13522
+ },
13523
+ pre: {
13524
+ marginTop: '0.5rem',
13525
+ padding: '0.75rem',
13526
+ fontFamily: fonts.mono,
13527
+ backgroundColor: 'oklch(0.269 0 0 / 0.5)',
13528
+ borderColor: colors.border,
13529
+ borderRadius: radii.sm,
13530
+ borderStyle: 'solid',
13531
+ borderWidth: 1,
13532
+ overflowX: 'auto',
13533
+ },
13534
+ footer: {
13535
+ display: 'flex',
13536
+ flexDirection: 'column',
13537
+ gap: '0.5rem',
13538
+ paddingBlock: '1rem',
13539
+ paddingInline: '0.5rem',
13540
+ },
13541
+ list: {
13542
+ display: 'flex',
13543
+ flexDirection: 'column',
13544
+ gap: '0.5rem',
13545
+ listStylePosition: 'inside',
13546
+ listStyleType: 'disc',
13547
+ },
13548
+ mono: {
13549
+ fontFamily: fonts.mono,
13550
+ },
13551
+ muted: {
13552
+ color: colors.mutedForeground,
13553
+ },
13554
+ });
13555
+ `
13556
+ };
13557
+ //#endregion
12309
13558
  //#region src/templates/todo-example/index.ts
12310
13559
  const todoExampleApi = { templates: [
12311
13560
  todos_module_default,
@@ -12328,6 +13577,7 @@ const todoExampleDi = { templates: [
12328
13577
  ] };
12329
13578
  const todoExampleWeb = { templates: [web_todo_list_default, web_page_default] };
12330
13579
  const todoExampleShadcn = { templates: [shadcn_todo_list_default, shadcn_page_default] };
13580
+ const todoExampleStylex = { templates: [stylex_todo_list_default, stylex_page_default] };
12331
13581
  //#endregion
12332
13582
  //#region src/templates/index.ts
12333
13583
  const staticDir = new URL("./static/", import.meta.url);
@@ -12341,7 +13591,7 @@ const E2E_FILES = [
12341
13591
  "apps/api/vitest.config.e2e.mts"
12342
13592
  ];
12343
13593
  function selectModules(selection) {
12344
- const { deployment, nest, todoExample, shadcn, database, linter, testing, extras } = selection;
13594
+ const { deployment, nest, todoExample, shadcn, stylex, database, linter, testing, extras } = selection;
12345
13595
  const deploymentModule = deployment === "standalone" ? deploymentStandalone : deployment === "spa" ? singleProcessStaticExport : null;
12346
13596
  const webModule = deployment === "spa" ? {
12347
13597
  ...web$1,
@@ -12360,7 +13610,7 @@ function selectModules(selection) {
12360
13610
  ...nest === "off" ? [] : [api$1],
12361
13611
  database === "postgres" ? dbPostgres : dbSqlite,
12362
13612
  auth,
12363
- shadcn ? shadcnUi : ui$1,
13613
+ shadcn ? shadcnUi : stylex ? stylexUi : ui$1,
12364
13614
  linter === "oxc" ? oxc : eslintConfig,
12365
13615
  ...extras.includes("anti-slop") ? [antiSlop] : [],
12366
13616
  typescriptConfig,
@@ -12371,7 +13621,7 @@ function selectModules(selection) {
12371
13621
  ...todoExample ? [
12372
13622
  todoExampleApi,
12373
13623
  ...nest === "di-only" ? [todoExampleDi] : [todoExampleControllers],
12374
- shadcn ? todoExampleShadcn : todoExampleWeb
13624
+ shadcn ? todoExampleShadcn : stylex ? todoExampleStylex : todoExampleWeb
12375
13625
  ] : []
12376
13626
  ];
12377
13627
  }
@@ -12478,6 +13728,13 @@ function validateExtrasCombo(extras, linter) {
12478
13728
  };
12479
13729
  return { valid: true };
12480
13730
  }
13731
+ function validateStylingCombo(shadcn, stylex) {
13732
+ if (shadcn && stylex) return {
13733
+ valid: false,
13734
+ error: "--shadcn cannot be combined with --stylex.\nshadcn/ui components are written in Tailwind utility classes, which StyleX does\nnot compile. Pick one styling system: drop --stylex for shadcn/ui, or drop\n--shadcn for StyleX."
13735
+ };
13736
+ return { valid: true };
13737
+ }
12481
13738
  function validateDeploymentCombo(deployment, nest) {
12482
13739
  if (deployment === "spa" && nest === "di-only") return {
12483
13740
  valid: false,
@@ -12633,6 +13890,7 @@ function buildPayload(report) {
12633
13890
  ci: detectCi(),
12634
13891
  explicitFlags: [...report.explicitFlags].sort().join(","),
12635
13892
  shadcn: selection.shadcn,
13893
+ stylex: selection.stylex,
12636
13894
  testing: selection.testing,
12637
13895
  database: selection.database,
12638
13896
  linter: selection.linter,
@@ -12706,6 +13964,10 @@ async function doInit(options) {
12706
13964
  message: "Use shadcn/ui?",
12707
13965
  initialValue: true
12708
13966
  }),
13967
+ stylex: ({ results }) => results.shadcn ? void 0 : p.confirm({
13968
+ message: "Use StyleX instead of Tailwind?",
13969
+ initialValue: false
13970
+ }),
12709
13971
  nest: () => p.select({
12710
13972
  message: "NestJS?",
12711
13973
  options: [
@@ -12811,6 +14073,7 @@ async function doInit(options) {
12811
14073
  process.exit(0);
12812
14074
  } });
12813
14075
  const useShadcn = options.nonInteractive ? options.shadcn : answers.shadcn ?? true;
14076
+ const useStylex = options.nonInteractive ? options.stylex : answers.stylex ?? false;
12814
14077
  const testing = options.nonInteractive ? options.testing : answers.testing ?? "jest";
12815
14078
  const database = options.nonInteractive ? options.database : answers.database ?? "sqlite";
12816
14079
  const linter = options.nonInteractive ? options.linter : answers.linter ?? "eslint";
@@ -12818,6 +14081,8 @@ async function doInit(options) {
12818
14081
  const nest = options.nonInteractive ? options.nest : answers.nest ?? "on";
12819
14082
  const todoExample = options.nonInteractive ? options.includeExample : nest !== "off" && (answers.todoExample ?? true);
12820
14083
  const extras = options.nonInteractive ? options.extras : answers.extras ?? [];
14084
+ const stylingCombo = validateStylingCombo(useShadcn, useStylex);
14085
+ if (!stylingCombo.valid) throw new Error(stylingCombo.error);
12821
14086
  const deploymentCombo = validateDeploymentCombo(deployment, nest);
12822
14087
  if (!deploymentCombo.valid) throw new Error(deploymentCombo.error);
12823
14088
  const exampleCombo = validateExampleCombo(todoExample, nest);
@@ -12829,6 +14094,7 @@ async function doInit(options) {
12829
14094
  nest,
12830
14095
  todoExample,
12831
14096
  shadcn: useShadcn,
14097
+ stylex: useStylex,
12832
14098
  database,
12833
14099
  linter,
12834
14100
  testing,
@@ -12897,10 +14163,11 @@ async function doInit(options) {
12897
14163
  }
12898
14164
  }
12899
14165
  const program = new Command();
12900
- 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: none, standalone, or spa", "none").option("--nest <mode>", "NestJS: on, off, or di-only", "on").option("--include-example", "Include the todo example", false).option("--extras <list>", "Extras, comma-separated: anti-slop", "").action(async (name, options, command) => {
14166
+ 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("--stylex", "Use StyleX instead of Tailwind", 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: none, standalone, or spa", "none").option("--nest <mode>", "NestJS: on, off, or di-only", "on").option("--include-example", "Include the todo example", false).option("--extras <list>", "Extras, comma-separated: anti-slop", "").action(async (name, options, command) => {
12901
14167
  intro(`Create a ${chalk.blue("newt")} app.`);
12902
14168
  const explicitFlags = Object.entries({
12903
14169
  shadcn: "--shadcn",
14170
+ stylex: "--stylex",
12904
14171
  testing: "--testing",
12905
14172
  database: "--database",
12906
14173
  linter: "--linter",
@@ -12953,6 +14220,7 @@ program.name("create-newt-app").version(version).description("Create a new newt-
12953
14220
  git: options.git,
12954
14221
  nonInteractive,
12955
14222
  shadcn: options.shadcn,
14223
+ stylex: options.stylex,
12956
14224
  testing: options.testing,
12957
14225
  database: options.database,
12958
14226
  linter: options.linter,