diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/main.wasp b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/main.wasp index 1f02583e4f..88044a7c03 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/main.wasp +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/main.wasp @@ -1,6 +1,6 @@ app waspBuild { wasp: { - version: "^0.15.2" + version: "^0.16.0" }, title: "waspBuild" } diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/main.wasp b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/main.wasp index 982cf4e8f0..70a8f46525 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/main.wasp +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/main.wasp @@ -1,6 +1,6 @@ app waspCompile { wasp: { - version: "^0.15.2" + version: "^0.16.0" }, title: "waspCompile" } diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/main.wasp b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/main.wasp index dd7184c671..48fddedeec 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/main.wasp +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/main.wasp @@ -1,6 +1,6 @@ app waspComplexTest { wasp: { - version: "^0.15.2" + version: "^0.16.0" }, auth: { userEntity: User, diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/main.wasp b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/main.wasp index 815644889f..f0a485ec43 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/main.wasp +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/main.wasp @@ -1,6 +1,6 @@ app waspJob { wasp: { - version: "^0.15.2" + version: "^0.16.0" }, title: "waspJob" } diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/main.wasp b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/main.wasp index 2a6ad7d962..99e0d47b2d 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/main.wasp +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/main.wasp @@ -1,6 +1,6 @@ app waspMigrate { wasp: { - version: "^0.15.2" + version: "^0.16.0" }, title: "waspMigrate" } diff --git a/waspc/e2e-test/test-outputs/waspNew-golden/waspNew/main.wasp b/waspc/e2e-test/test-outputs/waspNew-golden/waspNew/main.wasp index 96b3500b7f..995a2401e8 100644 --- a/waspc/e2e-test/test-outputs/waspNew-golden/waspNew/main.wasp +++ b/waspc/e2e-test/test-outputs/waspNew-golden/waspNew/main.wasp @@ -1,6 +1,6 @@ app waspNew { wasp: { - version: "^0.15.2" + version: "^0.16.0" }, title: "waspNew" } diff --git a/waspc/examples/todoApp/main.wasp b/waspc/examples/todoApp/main.wasp index f827d34e83..9dd232da7d 100644 --- a/waspc/examples/todoApp/main.wasp +++ b/waspc/examples/todoApp/main.wasp @@ -1,6 +1,6 @@ app todoApp { wasp: { - version: "^0.15.0" + version: "^0.16.0" }, title: "ToDo App", // head: [], diff --git a/waspc/examples/todoApp/main.wasp.ts.1 b/waspc/examples/todoApp/main.wasp.ts.1 new file mode 100644 index 0000000000..b911a30ee4 --- /dev/null +++ b/waspc/examples/todoApp/main.wasp.ts.1 @@ -0,0 +1,316 @@ +import { App } from 'wasp-config' + +const app = new App('todoApp', { + title: 'ToDo App', + wasp: { version: '^0.15.0' }, + // head: [] +}); + +app.webSocket({ + fn: { import: 'webSocketFn', from: '@src/webSocket' }, + // autoConnect: false +}); + +app.auth({ + userEntity: 'User', + methods: { + discord: { + configFn: { import: 'config', from: '@src/auth/discord' }, + userSignupFields: { import: 'userSignupFields', from: '@src/auth/discord' } + }, + google: { + configFn: { import: 'config', from: '@src/auth/google' }, + userSignupFields: { import: 'userSignupFields', from: '@src/auth/google' } + }, + gitHub: { + configFn: { import: 'config', from: '@src/auth/github.js' }, + userSignupFields: { import: 'userSignupFields', from: '@src/auth/github.js' } + }, + email: { + userSignupFields: { import: 'userSignupFields', from: '@src/auth/email' }, + fromField: { + name: 'ToDO App', + email: 'mihovil@ilakovac.com' + }, + emailVerification: { + getEmailContentFn: { import: 'getVerificationEmailContent', from: '@src/auth/email' }, + clientRoute: 'EmailVerificationRoute' + }, + passwordReset: { + getEmailContentFn: { import: 'getPasswordResetEmailContent', from: '@src/auth/email' }, + clientRoute: 'PasswordResetRoute' + } + } + }, + onAuthFailedRedirectTo: '/login', + onAuthSucceededRedirectTo: '/profile', + onBeforeSignup: { import: 'onBeforeSignup', from: '@src/auth/hooks.js' }, + onAfterSignup: { import: 'onAfterSignup', from: '@src/auth/hooks.js' }, + onBeforeOAuthRedirect: { import: 'onBeforeOAuthRedirect', from: '@src/auth/hooks.js' }, + onBeforeLogin: { import: 'onBeforeLogin', from: '@src/auth/hooks.js' }, + onAfterLogin: { import: 'onAfterLogin', from: '@src/auth/hooks.js' } +}); + +app.server({ + setupFn: { importDefault: 'setup', from: '@src/serverSetup' }, + middlewareConfigFn: { import: 'serverMiddlewareFn', from: '@src/serverSetup' } +}); + +app.client({ + rootComponent: { import: 'App', from: '@src/App' }, + setupFn: { importDefault: 'setup', from: '@src/clientSetup' } +}); + +app.db({ + seeds: [ + { import: 'devSeedSimple', from: '@src/dbSeeds' }, + { import: 'prodSeed', from: '@src/dbSeeds' } + ] +}); + +app.emailSender({ + provider: 'SMTP', + defaultFrom: { email: 'mihovil@ilakovac.com' } +}); + +const signupPage = app.page('SignupPage', { + component: { importDefault: 'Signup', from: '@src/pages/auth/Signup' } +}); +app.route('SignupRoute', { path: '/signup', to: signupPage }); + +const loginPage = app.page('LoginPage', { + component: { importDefault: 'Login', from: '@src/pages/auth/Login' } +}); +app.route('LoginRoute', { path: '/login', to: loginPage }); + +const passwordResetPage = app.page('PasswordResetPage', { + component: { import: 'PasswordReset', from: '@src/pages/auth/PasswordReset' } +}); +app.route('PasswordResetRoute', { path: '/password-reset', to: passwordResetPage }); + +const emailVerificationPage = app.page('EmailVerificationPage', { + component: { import: 'EmailVerification', from: '@src/pages/auth/EmailVerification' } +}); +app.route('EmailVerificationRoute', { path: '/email-verification-', to: emailVerificationPage }); + +const requestPasswordResetPage = app.page('RequestPasswordResetPage', { + component: { import: 'RequestPasswordReset', from: '@src/pages/auth/RequestPasswordReset' } +}); +app.route('RequestPasswordResetRoute', { path: '/request-password-reset', to: requestPasswordResetPage }); + +const mainPage = app.page('MainPage', { + authRequired: true, + component: { importDefault: 'Main', from: '@src/pages/Main' } +}); +app.route('HomeRoute', { path: '/', to: mainPage }); + +const aboutPage = app.page('AboutPage', { + component: { importDefault: 'About', from: '@src/pages/About' } +}); +app.route('AboutRoute', { path: '/about', to: aboutPage }); + +const profilePage = app.page('ProfilePage', { + authRequired: true, + component: { import: 'ProfilePage', from: '@src/pages/ProfilePage' } +}); +app.route('ProfileRoute', { path: '/profile', to: profilePage }); + +const taskPage = app.page('TaskPage', { + authRequired: true, + component: { importDefault: 'Task', from: '@src/pages/Task' } +}); +app.route('TaskRoute', { path: '/task/:id', to: taskPage }); + +const catchAllPage = app.page('CatchAllPage', { + component: { import: 'CatchAllPage', from: '@src/pages/CatchAll' } +}); +app.route('CatchAllRoute', { path: '*', to: catchAllPage }); + +app.query('getTasks', { + fn: { import: 'getTasks', from: '@src/queries' }, + entities: ['Task'] +}); + +app.api('fooBar', { + fn: { import: 'fooBar', from: '@src/apis' }, + middlewareConfigFn: { import: 'fooBarMiddlewareFn', from: '@src/apis' }, + entities: ['Task'], + httpRoute: ['ALL', '/foo/bar'] +}); + +app.apiNamespace('bar', { + middlewareConfigFn: { import: 'barNamespaceMiddlewareFn', from: '@src/apis' }, + path: '/bar' +}); + +app.api('barBaz', { + fn: { import: 'barBaz', from: '@src/apis' }, + auth: false, + entities: ['Task'], + httpRoute: ['GET', '/bar/baz'] +}); + +app.api('webhookCallback', { + fn: { import: 'webhookCallback', from: '@src/apis' }, + middlewareConfigFn: { import: 'webhookCallbackMiddlewareFn', from: '@src/apis' }, + httpRoute: ['POST', '/webhook/callback'], + auth: false +}); + +app.query('getNumTasks', { + fn: { import: 'getNumTasks', from: '@src/queries' }, + entities: ['Task'], + auth: false +}); + +app.query('getTask', { + fn: { import: 'getTask', from: '@src/queries' }, + entities: ['Task'] +}); + +app.action('createTask', { + fn: { import: 'createTask', from: '@src/actions' }, + entities: ['Task'] +}); + +app.action('updateTaskIsDone', { + fn: { import: 'updateTaskIsDone', from: '@src/actions' }, + entities: ['Task'] +}); + +app.action('deleteCompletedTasks', { + fn: { import: 'deleteCompletedTasks', from: '@src/actions' }, + entities: ['Task'] +}); + +app.action('toggleAllTasks', { + fn: { import: 'toggleAllTasks', from: '@src/actions' }, + entities: ['Task'] +}); + +app.job('mySpecialJob', { + executor: 'PgBoss', + perform: { + fn: { import: 'foo', from: '@src/jobs/bar' }, + executorOptions: { + pgBoss: { retryLimit: 1 } + } + }, + entities: ['Task'] +}); + +app.job('mySpecialScheduledJob', { + executor: 'PgBoss', + perform: { + fn: { import: 'foo', from: '@src/jobs/bar' } + }, + schedule: { + cron: '0 * * * *', + args: { foo: 'bar' }, + executorOptions: { + pgBoss: { retryLimit: 2 } + } + } +}); + +app.action('testingAction', { + fn: { import: 'testingAction', from: '@src/testTypes/operations/server' }, + entities: [] +}); + +app.query('getDate', { + fn: { import: 'getDate', from: '@src/testTypes/operations/definitions' } +}); + +app.query('getAnythingNoAuth', { + fn: { import: 'getAnythingNoAuth', from: '@src/testTypes/operations/definitions' }, + auth: false, + entities: [] +}); + +app.query('getAnythingAuth', { + fn: { import: 'getAnythingAuth', from: '@src/testTypes/operations/definitions' }, + auth: true, + entities: [] +}); + +app.query('getTrueVoid', { + fn: { import: 'getTrueVoid', from: '@src/testTypes/operations/definitions' }, + entities: [] +}); + +app.query('getAnyNoAuth', { + fn: { import: 'getAnyNoAuth', from: '@src/testTypes/operations/definitions' }, + auth: false, + entities: [] +}); + +app.query('getAnyAuth', { + fn: { import: 'getAnyAuth', from: '@src/testTypes/operations/definitions' }, + auth: true, + entities: [] +}); + +app.query('getAnyToNumberSpecified', { + fn: { import: 'getAnyToNumberSpecified', from: '@src/testTypes/operations/definitions' }, + auth: true, + entities: [] +}); + +app.action('taskToTaskUnspecified', { + fn: { import: 'taskToTaskUnspecified', from: '@src/testTypes/operations/definitions' }, + entities: ['Task'] +}); + +app.action('taskToTaskSatisfies', { + fn: { import: 'taskToTaskSatisfies', from: '@src/testTypes/operations/definitions' }, + entities: ['Task'] +}); + +app.action('taskToTaskSpecified', { + fn: { import: 'taskToTaskSpecified', from: '@src/testTypes/operations/definitions' }, + entities: ['Task'] +}); + +app.action('voidToStringAuth', { + fn: { import: 'voidToStringAuth', from: '@src/testTypes/operations/definitions' }, + auth: true, + entities: ['Task'] +}); + +app.action('voidToStringNoAuth', { + fn: { import: 'voidToStringNoAuth', from: '@src/testTypes/operations/definitions' }, + auth: false, + entities: ['Task'] +}); + +app.action('unspecifiedToNumber', { + fn: { import: 'unspecifiedToNumber', from: '@src/testTypes/operations/definitions' }, + entities: ['Task'] +}); + +app.action('boolToStringAuth', { + fn: { import: 'boolToStringAuth', from: '@src/testTypes/operations/definitions' }, + auth: true, + entities: ['Task'] +}); + +app.action('boolToStringNoAuth', { + fn: { import: 'boolToStringNoAuth', from: '@src/testTypes/operations/definitions' }, + auth: false, + entities: ['Task'] +}); + +app.action('boolToVoidNoAuth', { + fn: { import: 'boolToVoidNoAuth', from: '@src/testTypes/operations/definitions' }, + auth: false, + entities: ['Task'] +}); + +app.action('boolToVoidAuth', { + fn: { import: 'boolToVoidAuth', from: '@src/testTypes/operations/definitions' }, + auth: true, + entities: ['Task'] +}); + +export default app; diff --git a/waspc/examples/todoApp/main.waspina b/waspc/examples/todoApp/main.waspina new file mode 100644 index 0000000000..9cd2f4b1c6 --- /dev/null +++ b/waspc/examples/todoApp/main.waspina @@ -0,0 +1,327 @@ +app todoApp { + wasp: { + version: "^0.15.0" + }, + title: "ToDo App", + // head: [], + webSocket: { + fn: import { webSocketFn } from "@src/webSocket", + // autoConnect: false + }, + auth: { + userEntity: User, + methods: { + // usernameAndPassword: { + // userSignupFields: import { userSignupFields } from "@src/auth/github", + // }, + discord: { + configFn: import { config } from "@src/auth/discord", + userSignupFields: import { userSignupFields } from "@src/auth/discord" + }, + google: { + configFn: import { config } from "@src/auth/google", + userSignupFields: import { userSignupFields } from "@src/auth/google" + }, + gitHub: { + configFn: import { config } from "@src/auth/github.js", + userSignupFields: import { userSignupFields } from "@src/auth/github.js" + }, + // keycloak: {}, + email: { + userSignupFields: import { userSignupFields } from "@src/auth/email", + fromField: { + name: "ToDO App", + email: "mihovil@ilakovac.com" + }, + emailVerification: { + getEmailContentFn: import { getVerificationEmailContent } from "@src/auth/email", + clientRoute: EmailVerificationRoute, + }, + passwordReset: { + getEmailContentFn: import { getPasswordResetEmailContent } from "@src/auth/email", + clientRoute: PasswordResetRoute + }, + }, + }, + onAuthFailedRedirectTo: "/login", + onAuthSucceededRedirectTo: "/profile", + onBeforeSignup: import { onBeforeSignup } from "@src/auth/hooks.js", + onAfterSignup: import { onAfterSignup } from "@src/auth/hooks.js", + onBeforeOAuthRedirect: import { onBeforeOAuthRedirect } from "@src/auth/hooks.js", + onBeforeLogin: import { onBeforeLogin } from "@src/auth/hooks.js", + onAfterLogin: import { onAfterLogin } from "@src/auth/hooks.js", + }, + server: { + setupFn: import setup from "@src/serverSetup", + middlewareConfigFn: import { serverMiddlewareFn } from "@src/serverSetup", + }, + client: { + rootComponent: import { App } from "@src/App", + setupFn: import setup from "@src/clientSetup" + }, + db: { + seeds: [ + import { devSeedSimple } from "@src/dbSeeds", + import { prodSeed } from "@src/dbSeeds" + ] + }, + emailSender: { + provider: SMTP, + defaultFrom: { + email: "mihovil@ilakovac.com" + }, + }, +} + +route SignupRoute { path: "/signup", to: SignupPage } +page SignupPage { + component: import Signup from "@src/pages/auth/Signup" +} + +route LoginRoute { path: "/login", to: LoginPage } +page LoginPage { + component: import Login from "@src/pages/auth/Login" +} + +route PasswordResetRoute { path: "/password-reset", to: PasswordResetPage } +page PasswordResetPage { + component: import { PasswordReset } from "@src/pages/auth/PasswordReset", +} + +route EmailVerificationRoute { path: "/email-verification-", to: EmailVerificationPage } +page EmailVerificationPage { + component: import { EmailVerification } from "@src/pages/auth/EmailVerification", +} + +route RequestPasswordResetRoute { path: "/request-password-reset", to: RequestPasswordResetPage } +page RequestPasswordResetPage { + component: import { RequestPasswordReset } from "@src/pages/auth/RequestPasswordReset", +} + +route HomeRoute { path: "/", to: MainPage } +page MainPage { + authRequired: true, + component: import Main from "@src/pages/Main" +} + +route AboutRoute { path: "/about", to: AboutPage } +page AboutPage { + component: import About from "@src/pages/About" +} + +route ProfileRoute { path: "/profile", to: ProfilePage } +page ProfilePage { + authRequired: true, + component: import { ProfilePage } from "@src/pages/ProfilePage" +} + +// Page for viewing a specific task +// +route TaskRoute { path: "/task/:id", to: TaskPage } +page TaskPage { + authRequired: true, + component: import Task from "@src/pages/Task" +} + +route CatchAllRoute { path: "*", to: CatchAllPage } +page CatchAllPage { + component: import { CatchAllPage } from "@src/pages/CatchAll" +} + +// --------- Queries --------- // + +query getTasks { + fn: import { getTasks } from "@src/queries", + entities: [Task] +} + +api fooBar { + fn: import { fooBar } from "@src/apis", + middlewareConfigFn: import { fooBarMiddlewareFn } from "@src/apis", + entities: [Task], + // ALL here let's our CORS work. If we did GET, we would need an apiNamespace over it with CORS. + httpRoute: (ALL, "/foo/bar") +} + +apiNamespace bar { + middlewareConfigFn: import { barNamespaceMiddlewareFn } from "@src/apis", + path: "/bar" +} + +api barBaz { + fn: import { barBaz } from "@src/apis", + auth: false, + entities: [Task], + httpRoute: (GET, "/bar/baz") +} + +api webhookCallback { + fn: import { webhookCallback } from "@src/apis", + middlewareConfigFn: import { webhookCallbackMiddlewareFn } from "@src/apis", + httpRoute: (POST, "/webhook/callback"), + auth: false +} + +query getNumTasks { + fn: import { getNumTasks } from "@src/queries", + entities: [Task], + auth: false +} + +query getTask { + fn: import { getTask } from "@src/queries", + entities: [Task] +} + + +// --------- Actions --------- // + +action createTask { + fn: import { createTask } from "@src/actions", + entities: [Task] +} + +action updateTaskIsDone { + fn: import { updateTaskIsDone } from "@src/actions", + entities: [Task] +} + +action deleteCompletedTasks { + fn: import { deleteCompletedTasks } from "@src/actions", + entities: [Task] +} + +action toggleAllTasks { + fn: import { toggleAllTasks } from "@src/actions", + entities: [Task] +} + +job mySpecialJob { + executor: PgBoss, + perform: { + fn: import { foo } from "@src/jobs/bar", + executorOptions: { + pgBoss: {=json { "retryLimit": 1 } json=} + } + }, + entities: [Task] +} + +job mySpecialScheduledJob { + executor: PgBoss, + perform: { + fn: import { foo } from "@src/jobs/bar" + }, + schedule: { + cron: "0 * * * *", + args: {=json { "foo": "bar" } json=}, + executorOptions: { + pgBoss: {=json { "retryLimit": 2 } json=} + } + } +} + +// --------- Testing --------- // + +action testingAction { + fn: import { testingAction } from "@src/testTypes/operations/server", + entities: [] +} + +query getDate { + fn: import { getDate } from "@src/testTypes/operations/definitions" +} + + +query getAnythingNoAuth { + fn: import { getAnythingNoAuth } from "@src/testTypes/operations/definitions", + auth: false, + entities: [] +} + +query getAnythingAuth { + fn: import { getAnythingAuth } from "@src/testTypes/operations/definitions", + auth: true, + entities: [] +} + +query getTrueVoid { + fn: import { getTrueVoid } from "@src/testTypes/operations/definitions", + entities: [] +} + +query getAnyNoAuth { + fn: import { getAnyNoAuth } from "@src/testTypes/operations/definitions", + auth: false, + entities: [] +} + +query getAnyAuth { + fn: import { getAnyAuth } from "@src/testTypes/operations/definitions", + auth: true, + entities: [] +} + +query getAnyToNumberSpecified { + fn: import { getAnyToNumberSpecified } from "@src/testTypes/operations/definitions", + auth: true, + entities: [] +} + + +action taskToTaskUnspecified { + fn: import { taskToTaskUnspecified } from "@src/testTypes/operations/definitions", + entities: [Task] +} + +action taskToTaskSatisfies { + fn: import { taskToTaskSatisfies } from "@src/testTypes/operations/definitions", + entities: [Task] +} + +action taskToTaskSpecified { + fn: import { taskToTaskSpecified } from "@src/testTypes/operations/definitions", + entities: [Task] +} + +action voidToStringAuth { + fn: import { voidToStringAuth } from "@src/testTypes/operations/definitions", + auth: true, + entities: [Task] +} + +action voidToStringNoAuth { + fn: import { voidToStringNoAuth } from "@src/testTypes/operations/definitions", + auth: false, + entities: [Task] +} + +action unspecifiedToNumber { + fn: import { unspecifiedToNumber } from "@src/testTypes/operations/definitions", + entities: [Task] + +} + +action boolToStringAuth { + fn: import { boolToStringAuth } from "@src/testTypes/operations/definitions", + auth: true, + entities: [Task] +} + +action boolToStringNoAuth { + fn: import { boolToStringNoAuth } from "@src/testTypes/operations/definitions", + auth: false, + entities: [Task] +} + +action boolToVoidNoAuth { + fn: import { boolToVoidNoAuth } from "@src/testTypes/operations/definitions", + auth: false, + entities: [Task] +} + +action boolToVoidAuth { + fn: import { boolToVoidAuth } from "@src/testTypes/operations/definitions", + auth: true, + entities: [Task] +} diff --git a/waspc/examples/todoApp/tsconfig.src.json b/waspc/examples/todoApp/tsconfig.src.json new file mode 100644 index 0000000000..63c281ba2b --- /dev/null +++ b/waspc/examples/todoApp/tsconfig.src.json @@ -0,0 +1,57 @@ +// =============================== IMPORTANT ================================= +// This file is mainly used for Wasp IDE support. +// +// Wasp will compile your code with slightly different (less strict) compilerOptions. +// You can increase the configuration's strictness (e.g., by adding +// "noUncheckedIndexedAccess": true), but you shouldn't reduce it (e.g., by +// adding "strict": false). Just keep in mind that this will only affect your +// IDE support, not the actual compilation. +// +// Full TypeScript configurability is coming very soon :) +{ + "compilerOptions": { + "module": "esnext", + "composite": true, + "target": "esnext", + // We're bundling all code in the end so this is the most appropriate option, + // it's also important for autocomplete to work properly. + "moduleResolution": "bundler", + // JSX support + "jsx": "preserve", + "strict": true, + // Allow default imports. + "esModuleInterop": true, + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "skipLibCheck": true, + "allowJs": true, + "typeRoots": [ + // This is needed to properly support Vitest testing with jest-dom matchers. + // Types for jest-dom are not recognized automatically and Typescript complains + // about missing types e.g. when using `toBeInTheDocument` and other matchers. + "node_modules/@testing-library", + // Specifying type roots overrides the default behavior of looking at the + // node_modules/@types folder so we had to list it explicitly. + // Source 1: https://www.typescriptlang.org/tsconfig#typeRoots + // Source 2: https://github.com/testing-library/jest-dom/issues/546#issuecomment-1889884843 + "node_modules/@types" + ], + // Since this TS config is used only for IDE support and not for + // compilation, the following directory doesn't exist. We need to specify + // it to prevent this error: + // https://stackoverflow.com/questions/42609768/typescript-error-cannot-write-file-because-it-would-overwrite-input-file + // "outDir": ".wasp/out/user" + "outDir": ".wasp/out/user", + // "baseUrl": ".", + // "paths": { + // "@components/*": ["src/components/*"], + // "@util": ["src/util.js"], + // } + }, + "include": [ + "src" + ] +} diff --git a/waspc/examples/todoApp/tsconfig.wasp.json b/waspc/examples/todoApp/tsconfig.wasp.json new file mode 100644 index 0000000000..9eb69316d1 --- /dev/null +++ b/waspc/examples/todoApp/tsconfig.wasp.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "skipLibCheck": true, + "target": "ES2022", + "isolatedModules": true, + "moduleDetection": "force", + + // linting + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + + "module": "NodeNext", + "noEmit": true, + + "lib": ["ES2023"], + }, + "include": ["*.wasp.ts"] +} diff --git a/waspc/waspc.cabal b/waspc/waspc.cabal index 55c87fff55..d8af354554 100644 --- a/waspc/waspc.cabal +++ b/waspc/waspc.cabal @@ -6,7 +6,7 @@ cabal-version: 2.4 -- Consider using hpack, or maybe even hpack-dhall. name: waspc -version: 0.15.2 +version: 0.16.0 description: Please see the README on GitHub at homepage: https://github.com/wasp-lang/wasp/waspc#readme bug-reports: https://github.com/wasp-lang/wasp/issues