From 23572bd47c26952991aa512a44b9a055183e8458 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Tue, 22 Apr 2025 22:06:10 +0300 Subject: [PATCH] chore(monorepo/client): create empty project --- .gitignore | 4 + .vscode/extensions.json | 5 + apps/client-e2e/eslint.config.mjs | 15 + apps/client-e2e/package.json | 10 + apps/client-e2e/playwright.config.ts | 68 +++ apps/client-e2e/src/example.spec.ts | 8 + apps/client-e2e/tsconfig.json | 25 ++ apps/client/.swcrc | 8 + apps/client/eslint.config.mjs | 5 + apps/client/package.json | 5 + apps/client/src/app/app.element.css | 424 ++++++++++++++++++ apps/client/src/app/app.element.spec.ts | 21 + apps/client/src/app/app.element.ts | 409 ++++++++++++++++++ apps/client/src/assets/.gitkeep | 0 apps/client/src/favicon.ico | Bin 0 -> 15086 bytes apps/client/src/index.html | 14 + apps/client/src/main.ts | 1 + apps/client/src/styles.css | 1 + apps/client/tsconfig.app.json | 36 ++ apps/client/tsconfig.json | 13 + apps/client/tsconfig.spec.json | 35 ++ apps/client/vite.config.ts | 23 + apps/client/webpack.config.js | 26 ++ eslint.config.mjs | 103 +++-- nx.json | 19 + package-lock.json | 543 ++++++++++++++++++++++-- package.json | 6 + tsconfig.json | 6 + 28 files changed, 1746 insertions(+), 87 deletions(-) create mode 100644 .vscode/extensions.json create mode 100644 apps/client-e2e/eslint.config.mjs create mode 100644 apps/client-e2e/package.json create mode 100644 apps/client-e2e/playwright.config.ts create mode 100644 apps/client-e2e/src/example.spec.ts create mode 100644 apps/client-e2e/tsconfig.json create mode 100644 apps/client/.swcrc create mode 100644 apps/client/eslint.config.mjs create mode 100644 apps/client/package.json create mode 100644 apps/client/src/app/app.element.css create mode 100644 apps/client/src/app/app.element.spec.ts create mode 100644 apps/client/src/app/app.element.ts create mode 100644 apps/client/src/assets/.gitkeep create mode 100644 apps/client/src/favicon.ico create mode 100644 apps/client/src/index.html create mode 100644 apps/client/src/main.ts create mode 100644 apps/client/src/styles.css create mode 100644 apps/client/tsconfig.app.json create mode 100644 apps/client/tsconfig.json create mode 100644 apps/client/tsconfig.spec.json create mode 100644 apps/client/vite.config.ts create mode 100644 apps/client/webpack.config.js diff --git a/.gitignore b/.gitignore index 68a8e969f..0560e4baa 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,7 @@ Thumbs.db .nx/cache .nx/workspace-data + +vite.config.*.timestamp* +vitest.config.*.timestamp* +test-output diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..de1c9f40a --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "ms-playwright.playwright" + ] +} diff --git a/apps/client-e2e/eslint.config.mjs b/apps/client-e2e/eslint.config.mjs new file mode 100644 index 000000000..1603594d7 --- /dev/null +++ b/apps/client-e2e/eslint.config.mjs @@ -0,0 +1,15 @@ +import playwright from "eslint-plugin-playwright"; +import baseConfig from "../../eslint.config.mjs"; + +export default [ + playwright.configs["flat/recommended"], + ...baseConfig, + { + files: [ + "**/*.ts", + "**/*.js" + ], + // Override or add rules here + rules: {} + } +]; diff --git a/apps/client-e2e/package.json b/apps/client-e2e/package.json new file mode 100644 index 000000000..1ada09ee3 --- /dev/null +++ b/apps/client-e2e/package.json @@ -0,0 +1,10 @@ +{ + "name": "@triliumnext/client-e2e", + "version": "0.0.1", + "private": true, + "nx": { + "implicitDependencies": [ + "@triliumnext/client" + ] + } +} diff --git a/apps/client-e2e/playwright.config.ts b/apps/client-e2e/playwright.config.ts new file mode 100644 index 000000000..cbedd6740 --- /dev/null +++ b/apps/client-e2e/playwright.config.ts @@ -0,0 +1,68 @@ +import { defineConfig, devices } from '@playwright/test'; +import { nxE2EPreset } from '@nx/playwright/preset'; +import { workspaceRoot } from '@nx/devkit'; + +// For CI, you may want to set BASE_URL to the deployed application. +const baseURL = process.env['BASE_URL'] || 'http://localhost:4200'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + ...nxE2EPreset(__filename, { testDir: './src' }), + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + baseURL, + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + /* Run your local dev server before starting the tests */ + webServer: { + command: 'npx nx run @triliumnext/client:serve-static', + url: 'http://localhost:4200', + reuseExistingServer: !process.env.CI, + cwd: workspaceRoot + }, + projects: [ + { + name: "chromium", + use: { ...devices["Desktop Chrome"] }, + }, + + { + name: "firefox", + use: { ...devices["Desktop Firefox"] }, + }, + + { + name: "webkit", + use: { ...devices["Desktop Safari"] }, + }, + + // Uncomment for mobile browsers support + /* { + name: 'Mobile Chrome', + use: { ...devices['Pixel 5'] }, + }, + { + name: 'Mobile Safari', + use: { ...devices['iPhone 12'] }, + }, */ + + // Uncomment for branded browsers + /* { + name: 'Microsoft Edge', + use: { ...devices['Desktop Edge'], channel: 'msedge' }, + }, + { + name: 'Google Chrome', + use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + } */ + ], +}); diff --git a/apps/client-e2e/src/example.spec.ts b/apps/client-e2e/src/example.spec.ts new file mode 100644 index 000000000..fa8f1f335 --- /dev/null +++ b/apps/client-e2e/src/example.spec.ts @@ -0,0 +1,8 @@ +import { test, expect } from '@playwright/test'; + +test('has title', async ({ page }) => { + await page.goto('/'); + + // Expect h1 to contain a substring. + expect(await page.locator('h1').innerText()).toContain('Welcome'); +}); diff --git a/apps/client-e2e/tsconfig.json b/apps/client-e2e/tsconfig.json new file mode 100644 index 000000000..1df867f3a --- /dev/null +++ b/apps/client-e2e/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "allowJs": true, + "outDir": "out-tsc/playwright", + "sourceMap": false + }, + "include": [ + "**/*.ts", + "**/*.js", + "playwright.config.ts", + "src/**/*.spec.ts", + "src/**/*.spec.js", + "src/**/*.test.ts", + "src/**/*.test.js", + "src/**/*.d.ts" + ], + "exclude": [ + "out-tsc", + "test-output", + "eslint.config.js", + "eslint.config.mjs", + "eslint.config.cjs" + ] +} diff --git a/apps/client/.swcrc b/apps/client/.swcrc new file mode 100644 index 000000000..a2d5b04f4 --- /dev/null +++ b/apps/client/.swcrc @@ -0,0 +1,8 @@ +{ + "jsc": { + "parser": { + "syntax": "typescript" + }, + "target": "es2016" + } +} diff --git a/apps/client/eslint.config.mjs b/apps/client/eslint.config.mjs new file mode 100644 index 000000000..724052a2e --- /dev/null +++ b/apps/client/eslint.config.mjs @@ -0,0 +1,5 @@ +import baseConfig from "../../eslint.config.mjs"; + +export default [ + ...baseConfig +]; diff --git a/apps/client/package.json b/apps/client/package.json new file mode 100644 index 000000000..5bbc39f08 --- /dev/null +++ b/apps/client/package.json @@ -0,0 +1,5 @@ +{ + "name": "@triliumnext/client", + "version": "0.0.1", + "private": true +} diff --git a/apps/client/src/app/app.element.css b/apps/client/src/app/app.element.css new file mode 100644 index 000000000..27d098404 --- /dev/null +++ b/apps/client/src/app/app.element.css @@ -0,0 +1,424 @@ +/* + * Remove template code below + */ + html { + -webkit-text-size-adjust: 100%; + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', + 'Noto Color Emoji'; + line-height: 1.5; + tab-size: 4; + scroll-behavior: smooth; + } + body { + font-family: inherit; + line-height: inherit; + margin: 0; + } + h1, + h2, + p, + pre { + margin: 0; + } + *, + ::before, + ::after { + box-sizing: border-box; + border-width: 0; + border-style: solid; + border-color: currentColor; + } + h1, + h2 { + font-size: inherit; + font-weight: inherit; + } + a { + color: inherit; + text-decoration: inherit; + } + pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, + 'Liberation Mono', 'Courier New', monospace; + } + svg { + display: block; + vertical-align: middle; + } + + svg { + shape-rendering: auto; + text-rendering: optimizeLegibility; + } + pre { + background-color: rgba(55, 65, 81, 1); + border-radius: 0.25rem; + color: rgba(229, 231, 235, 1); + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, + 'Liberation Mono', 'Courier New', monospace; + overflow: scroll; + padding: 0.5rem 0.75rem; + } + + .shadow { + box-shadow: 0 0 #0000, 0 0 #0000, 0 10px 15px -3px rgba(0, 0, 0, 0.1), + 0 4px 6px -2px rgba(0, 0, 0, 0.05); + } + .rounded { + border-radius: 1.5rem; + } + + .wrapper { + width: 100%; + } + .container { + margin-left: auto; + margin-right: auto; + max-width: 768px; + padding-bottom: 3rem; + padding-left: 1rem; + padding-right: 1rem; + color: rgba(55, 65, 81, 1); + width: 100%; + } + #welcome { + margin-top: 2.5rem; + } + #welcome h1 { + font-size: 3rem; + font-weight: 500; + letter-spacing: -0.025em; + line-height: 1; + } + #welcome span { + display: block; + font-size: 1.875rem; + font-weight: 300; + line-height: 2.25rem; + margin-bottom: 0.5rem; + } + #hero { + align-items: center; + background-color: hsla(214, 62%, 21%, 1); + border: none; + box-sizing: border-box; + color: rgba(55, 65, 81, 1); + display: grid; + grid-template-columns: 1fr; + margin-top: 3.5rem; + } + #hero .text-container { + color: rgba(255, 255, 255, 1); + padding: 3rem 2rem; + } + #hero .text-container h2 { + font-size: 1.5rem; + line-height: 2rem; + position: relative; + } + #hero .text-container h2 svg { + color: hsla(162, 47%, 50%, 1); + height: 2rem; + left: -0.25rem; + position: absolute; + top: 0; + width: 2rem; + } + #hero .text-container h2 span { + margin-left: 2.5rem; + } + #hero .text-container a { + background-color: rgba(255, 255, 255, 1); + border-radius: 0.75rem; + color: rgba(55, 65, 81, 1); + display: inline-block; + margin-top: 1.5rem; + padding: 1rem 2rem; + text-decoration: inherit; + } + #hero .logo-container { + display: none; + justify-content: center; + padding-left: 2rem; + padding-right: 2rem; + } + #hero .logo-container svg { + color: rgba(255, 255, 255, 1); + width: 66.666667%; + } + + #middle-content { + align-items: flex-start; + display: grid; + gap: 4rem; + grid-template-columns: 1fr; + margin-top: 3.5rem; + } + + #learning-materials { + padding: 2.5rem 2rem; + } + #learning-materials h2 { + font-weight: 500; + font-size: 1.25rem; + letter-spacing: -0.025em; + line-height: 1.75rem; + padding-left: 1rem; + padding-right: 1rem; + } + .list-item-link { + align-items: center; + border-radius: 0.75rem; + display: flex; + margin-top: 1rem; + padding: 1rem; + transition-property: background-color, border-color, color, fill, stroke, + opacity, box-shadow, transform, filter, backdrop-filter, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + width: 100%; + } + .list-item-link svg:first-child { + margin-right: 1rem; + height: 1.5rem; + transition-property: background-color, border-color, color, fill, stroke, + opacity, box-shadow, transform, filter, backdrop-filter, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + width: 1.5rem; + } + .list-item-link > span { + flex-grow: 1; + font-weight: 400; + transition-property: background-color, border-color, color, fill, stroke, + opacity, box-shadow, transform, filter, backdrop-filter, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + } + .list-item-link > span > span { + color: rgba(107, 114, 128, 1); + display: block; + flex-grow: 1; + font-size: 0.75rem; + font-weight: 300; + line-height: 1rem; + transition-property: background-color, border-color, color, fill, stroke, + opacity, box-shadow, transform, filter, backdrop-filter, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + } + .list-item-link svg:last-child { + height: 1rem; + transition-property: all; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + width: 1rem; + } + .list-item-link:hover { + color: rgba(255, 255, 255, 1); + background-color: hsla(162, 47%, 50%, 1); + } + .list-item-link:hover > span { + } + .list-item-link:hover > span > span { + color: rgba(243, 244, 246, 1); + } + .list-item-link:hover svg:last-child { + transform: translateX(0.25rem); + } + + #other-links { + } + .button-pill { + padding: 1.5rem 2rem; + transition-duration: 300ms; + transition-property: background-color, border-color, color, fill, stroke, + opacity, box-shadow, transform, filter, backdrop-filter, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + align-items: center; + display: flex; + } + .button-pill svg { + transition-property: background-color, border-color, color, fill, stroke, + opacity, box-shadow, transform, filter, backdrop-filter, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + flex-shrink: 0; + width: 3rem; + } + .button-pill > span { + letter-spacing: -0.025em; + font-weight: 400; + font-size: 1.125rem; + line-height: 1.75rem; + padding-left: 1rem; + padding-right: 1rem; + } + .button-pill span span { + display: block; + font-size: 0.875rem; + font-weight: 300; + line-height: 1.25rem; + } + .button-pill:hover svg, + .button-pill:hover { + color: rgba(255, 255, 255, 1) !important; + } + #nx-console:hover { + background-color: rgba(0, 122, 204, 1); + } + #nx-console svg { + color: rgba(0, 122, 204, 1); + } + #nx-console-jetbrains { + margin-top: 2rem; + } + #nx-console-jetbrains:hover { + background-color: rgba(255, 49, 140, 1); + } + #nx-console-jetbrains svg { + color: rgba(255, 49, 140, 1); + } + #nx-repo:hover { + background-color: rgba(24, 23, 23, 1); + } + #nx-repo svg { + color: rgba(24, 23, 23, 1); + } + + #nx-cloud { + margin-bottom: 2rem; + margin-top: 2rem; + padding: 2.5rem 2rem; + } + #nx-cloud > div { + align-items: center; + display: flex; + } + #nx-cloud > div svg { + border-radius: 0.375rem; + flex-shrink: 0; + width: 3rem; + } + #nx-cloud > div h2 { + font-size: 1.125rem; + font-weight: 400; + letter-spacing: -0.025em; + line-height: 1.75rem; + padding-left: 1rem; + padding-right: 1rem; + } + #nx-cloud > div h2 span { + display: block; + font-size: 0.875rem; + font-weight: 300; + line-height: 1.25rem; + } + #nx-cloud p { + font-size: 1rem; + line-height: 1.5rem; + margin-top: 1rem; + } + #nx-cloud pre { + margin-top: 1rem; + } + #nx-cloud a { + color: rgba(107, 114, 128, 1); + display: block; + font-size: 0.875rem; + line-height: 1.25rem; + margin-top: 1.5rem; + text-align: right; + } + #nx-cloud a:hover { + text-decoration: underline; + } + + #commands { + padding: 2.5rem 2rem; + + margin-top: 3.5rem; + } + #commands h2 { + font-size: 1.25rem; + font-weight: 400; + letter-spacing: -0.025em; + line-height: 1.75rem; + padding-left: 1rem; + padding-right: 1rem; + } + #commands p { + font-size: 1rem; + font-weight: 300; + line-height: 1.5rem; + margin-top: 1rem; + padding-left: 1rem; + padding-right: 1rem; + } + details { + align-items: center; + display: flex; + margin-top: 1rem; + padding-left: 1rem; + padding-right: 1rem; + width: 100%; + } + details pre > span { + color: rgba(181, 181, 181, 1); + } + summary { + border-radius: 0.5rem; + display: flex; + font-weight: 400; + padding: 0.5rem; + cursor: pointer; + transition-property: background-color, border-color, color, fill, stroke, + opacity, box-shadow, transform, filter, backdrop-filter, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + } + summary:hover { + background-color: rgba(243, 244, 246, 1); + } + summary svg { + height: 1.5rem; + margin-right: 1rem; + width: 1.5rem; + } + + #love { + color: rgba(107, 114, 128, 1); + font-size: 0.875rem; + line-height: 1.25rem; + margin-top: 3.5rem; + opacity: 0.6; + text-align: center; + } + #love svg { + color: rgba(252, 165, 165, 1); + width: 1.25rem; + height: 1.25rem; + display: inline; + margin-top: -0.25rem; + } + + @media screen and (min-width: 768px) { + #hero { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + #hero .logo-container { + display: flex; + } + #middle-content { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + } diff --git a/apps/client/src/app/app.element.spec.ts b/apps/client/src/app/app.element.spec.ts new file mode 100644 index 000000000..2c12da184 --- /dev/null +++ b/apps/client/src/app/app.element.spec.ts @@ -0,0 +1,21 @@ +import { AppElement } from './app.element'; + +describe('AppElement', () => { + let app: AppElement; + + beforeEach(() => { + app = new AppElement(); + }); + + it('should create successfully', () => { + expect(app).toBeTruthy(); + }); + + it('should have a greeting', () => { + app.connectedCallback(); + + expect(app.querySelector('h1').innerHTML).toContain( + 'Welcome @triliumnext/client' + ); + }); +}); diff --git a/apps/client/src/app/app.element.ts b/apps/client/src/app/app.element.ts new file mode 100644 index 000000000..fab80aa49 --- /dev/null +++ b/apps/client/src/app/app.element.ts @@ -0,0 +1,409 @@ +import './app.element.css'; + +export class AppElement extends HTMLElement { + public static observedAttributes = [ + + ]; + + connectedCallback() { + const title = '@triliumnext/client'; + this.innerHTML = ` +
+
+ +
+

+ Hello there, + Welcome ${title} 👋 +

+
+ + +
+
+

+ + + + You're up and running +

+ What's next? +
+
+ + + +
+
+ + + + + +
+

Next steps

+

Here are some things you can do with Nx:

+
+ + + + + Add UI library + +
# Generate UI lib
+nx g @nx/angular:lib ui
+
+# Add a component
+nx g @nx/angular:component ui/src/lib/button
+
+
+ + + + + View interactive project graph + +
nx graph
+
+
+ + + + + Run affected commands + +
# see what's been affected by changes
+nx affected:graph
+
+# run tests for current changes
+nx affected:test
+
+# run e2e tests for current changes
+nx affected:e2e
+
+
+ +

+ Carefully crafted with + + + +

+
+
+ `; + } +} +customElements.define('triliumnext-root', AppElement); diff --git a/apps/client/src/assets/.gitkeep b/apps/client/src/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/apps/client/src/favicon.ico b/apps/client/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..317ebcb2336e0833a22dddf0ab287849f26fda57 GIT binary patch literal 15086 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 + + + + Client + + + + + + + + + diff --git a/apps/client/src/main.ts b/apps/client/src/main.ts new file mode 100644 index 000000000..fdb879ded --- /dev/null +++ b/apps/client/src/main.ts @@ -0,0 +1 @@ +import './app/app.element'; diff --git a/apps/client/src/styles.css b/apps/client/src/styles.css new file mode 100644 index 000000000..90d4ee007 --- /dev/null +++ b/apps/client/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/client/tsconfig.app.json b/apps/client/tsconfig.app.json new file mode 100644 index 000000000..ec59d3293 --- /dev/null +++ b/apps/client/tsconfig.app.json @@ -0,0 +1,36 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "types": [ + "node" + ], + "rootDir": "src", + "module": "esnext", + "moduleResolution": "bundler", + "tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo" + }, + "exclude": [ + "out-tsc", + "dist", + "jest.config.ts", + "src/**/*.spec.ts", + "src/**/*.test.ts", + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "eslint.config.js", + "eslint.config.cjs", + "eslint.config.mjs" + ], + "include": [ + "src/**/*.ts" + ] +} diff --git a/apps/client/tsconfig.json b/apps/client/tsconfig.json new file mode 100644 index 000000000..63dbe35fb --- /dev/null +++ b/apps/client/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/apps/client/tsconfig.spec.json b/apps/client/tsconfig.spec.json new file mode 100644 index 000000000..164775969 --- /dev/null +++ b/apps/client/tsconfig.spec.json @@ -0,0 +1,35 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./out-tsc/vitest", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ], + "module": "esnext", + "moduleResolution": "bundler" + }, + "include": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ], + "references": [ + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/apps/client/vite.config.ts b/apps/client/vite.config.ts new file mode 100644 index 000000000..26be2b87e --- /dev/null +++ b/apps/client/vite.config.ts @@ -0,0 +1,23 @@ + +import { defineConfig } from 'vite'; + +export default defineConfig(() => ({ + root: __dirname, + cacheDir: '../../node_modules/.vite/apps/client', + plugins: [], + // Uncomment this if you are using workers. + // worker: { + // plugins: [ nxViteTsPaths() ], + // }, + test: { + 'watch': false, + 'globals': true, + 'environment': "jsdom", + 'include': ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], + 'reporters': ["default"], + 'coverage': { + 'reportsDirectory': './test-output/vitest/coverage', + 'provider': 'v8' as const, +} + }, +})); diff --git a/apps/client/webpack.config.js b/apps/client/webpack.config.js new file mode 100644 index 000000000..2bcef6b62 --- /dev/null +++ b/apps/client/webpack.config.js @@ -0,0 +1,26 @@ + +const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); +const { join } = require('path'); + +module.exports = { + output: { + path: join(__dirname, 'dist'), + }, + devServer: { + port: 4200 + }, + plugins: [ + new NxAppWebpackPlugin({ + tsConfig: './tsconfig.app.json', + compiler: 'swc', + main: './src/main.ts', + index: './src/index.html', + baseHref: '/', + assets: ["./src/favicon.ico","./src/assets"], + styles: ["./src/styles.css"], + outputHashing: process.env['NODE_ENV'] === 'production' ? 'all' : 'none', + optimization: process.env['NODE_ENV'] === 'production', + }) + ], +}; + diff --git a/eslint.config.mjs b/eslint.config.mjs index 1058fd63b..805361011 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,55 +1,54 @@ -import nx from "@nx/eslint-plugin"; - -export default [ - ...nx.configs["flat/base"], - ...nx.configs["flat/typescript"], - ...nx.configs["flat/javascript"], - { - "ignores": [ +import nx from "@nx/eslint-plugin"; + +export default [ + ...nx.configs["flat/base"], + ...nx.configs["flat/typescript"], + ...nx.configs["flat/javascript"], + { "ignores": [ "**/dist", "**/vite.config.*.timestamp*", "**/vitest.config.*.timestamp*" - ] - }, - { - files: [ - "**/*.ts", - "**/*.tsx", - "**/*.js", - "**/*.jsx" - ], - rules: { - "@nx/enforce-module-boundaries": [ - "error", - { - enforceBuildableLibDependency: true, - allow: [ - "^.*/eslint(\\.base)?\\.config\\.[cm]?js$" - ], - depConstraints: [ - { - sourceTag: "*", - onlyDependOnLibsWithTags: [ - "*" - ] - } - ] - } - ] - } - }, - { - files: [ - "**/*.ts", - "**/*.tsx", - "**/*.cts", - "**/*.mts", - "**/*.js", - "**/*.jsx", - "**/*.cjs", - "**/*.mjs" - ], - // Override or add rules here - rules: {} - } -]; + ] + }, + { + files: [ + "**/*.ts", + "**/*.tsx", + "**/*.js", + "**/*.jsx" + ], + rules: { + "@nx/enforce-module-boundaries": [ + "error", + { + enforceBuildableLibDependency: true, + allow: [ + "^.*/eslint(\\.base)?\\.config\\.[cm]?js$" + ], + depConstraints: [ + { + sourceTag: "*", + onlyDependOnLibsWithTags: [ + "*" + ] + } + ] + } + ] + } + }, + { + files: [ + "**/*.ts", + "**/*.tsx", + "**/*.cts", + "**/*.mts", + "**/*.js", + "**/*.jsx", + "**/*.cjs", + "**/*.mjs" + ], + // Override or add rules here + rules: {} + } +]; diff --git a/nx.json b/nx.json index 2fdfd0fc1..29f05c4d0 100644 --- a/nx.json +++ b/nx.json @@ -60,6 +60,12 @@ "buildDepsTargetName": "build-deps", "watchDepsTargetName": "watch-deps" } + }, + { + "plugin": "@nx/playwright/plugin", + "options": { + "targetName": "e2e" + } } ], "targetDefaults": { @@ -87,6 +93,19 @@ "production", "^production" ] + }, + "e2e-ci--**/*": { + "dependsOn": [ + "^build" + ] + } + }, + "generators": { + "@nx/web:application": { + "style": "css", + "linter": "eslint", + "unitTestRunner": "vitest", + "e2eTestRunner": "playwright" } } } diff --git a/package-lock.json b/package-lock.json index c27f4b3b0..e794ec487 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,15 +18,18 @@ }, "devDependencies": { "@eslint/js": "^9.8.0", + "@nx/devkit": "20.8.0", "@nx/esbuild": "20.8.0", "@nx/eslint": "20.8.0", "@nx/eslint-plugin": "20.8.0", "@nx/express": "20.8.0", "@nx/js": "20.8.0", "@nx/node": "20.8.0", + "@nx/playwright": "20.8.0", "@nx/vite": "20.8.0", "@nx/web": "20.8.0", "@nx/webpack": "20.8.0", + "@playwright/test": "^1.36.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.7", "@svgr/webpack": "^8.0.1", "@swc-node/register": "~1.9.1", @@ -40,10 +43,13 @@ "esbuild": "^0.19.2", "eslint": "^9.8.0", "eslint-config-prettier": "^10.0.0", + "eslint-plugin-playwright": "^1.6.2", "jiti": "2.4.2", + "jsdom": "~22.1.0", "jsonc-eslint-parser": "^2.1.0", "nx": "20.8.0", "react-refresh": "^0.10.0", + "swc-loader": "0.1.15", "tslib": "^2.3.0", "typescript": "~5.7.2", "typescript-eslint": "^8.19.0", @@ -52,6 +58,14 @@ "webpack-cli": "^5.1.4" } }, + "apps/client": { + "name": "@triliumnext/client", + "version": "0.0.1" + }, + "apps/client-e2e": { + "name": "@triliumnext/client-e2e", + "version": "0.0.1" + }, "apps/server": { "name": "@triliumnext/server", "version": "0.0.1", @@ -170,6 +184,18 @@ "version": "0.0.1", "extraneous": true }, + "apps/server/node_modules/entities": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz", + "integrity": "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "apps/server/node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -206,6 +232,18 @@ "node": ">=14.14" } }, + "apps/server/node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, "apps/server/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -218,6 +256,45 @@ "js-yaml": "bin/js-yaml.js" } }, + "apps/server/node_modules/jsdom": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", + "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", + "license": "MIT", + "dependencies": { + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.5.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.1.1", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.1", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, "apps/server/node_modules/mime-db": { "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", @@ -239,6 +316,18 @@ "node": ">= 0.6" } }, + "apps/server/node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "apps/server/node_modules/strip-bom": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-5.0.0.tgz", @@ -318,6 +407,18 @@ "node": ">= 0.6" } }, + "apps/server/node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@adobe/css-tools": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", @@ -5684,6 +5785,29 @@ "node": ">= 10" } }, + "node_modules/@nx/playwright": { + "version": "20.8.0", + "resolved": "https://registry.npmjs.org/@nx/playwright/-/playwright-20.8.0.tgz", + "integrity": "sha512-HQd6GCk4j2qNwpRY6OwaiazxXc9R/4KC0mNHN9cE7IWK2mUix+RavFYBZ8+dh7Q+O1mU0euyM7rjbT7xs1sPrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nx/devkit": "20.8.0", + "@nx/eslint": "20.8.0", + "@nx/js": "20.8.0", + "@phenomnomnominal/tsquery": "~5.0.1", + "minimatch": "9.0.3", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@playwright/test": "^1.36.0" + }, + "peerDependenciesMeta": { + "@playwright/test": { + "optional": true + } + } + }, "node_modules/@nx/vite": { "version": "20.8.0", "resolved": "https://registry.npmjs.org/@nx/vite/-/vite-20.8.0.tgz", @@ -6135,6 +6259,22 @@ "node": ">=14" } }, + "node_modules/@playwright/test": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz", + "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.52.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.16.tgz", @@ -8098,6 +8238,24 @@ "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", "license": "MIT" }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@triliumnext/client": { + "resolved": "apps/client", + "link": true + }, + "node_modules/@triliumnext/client-e2e": { + "resolved": "apps/client-e2e", + "link": true + }, "node_modules/@triliumnext/commons": { "resolved": "packages/commons", "link": true @@ -9710,6 +9868,14 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -13441,6 +13607,20 @@ ], "license": "BSD-2-Clause" }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "license": "MIT", + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", @@ -14051,6 +14231,60 @@ "eslint": ">=7.0.0" } }, + "node_modules/eslint-plugin-playwright": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-1.8.3.tgz", + "integrity": "sha512-h87JPFHkz8a6oPhn8GRGGhSQoAJjx0AkOv1jME6NoMk2FpEsfvfJJNaQDxLSqSALkCr0IJXPGTnp6SIRVu5Nqg==", + "dev": true, + "license": "MIT", + "workspaces": [ + "examples" + ], + "dependencies": { + "globals": "^13.23.0" + }, + "engines": { + "node": ">=16.6.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0", + "eslint-plugin-jest": ">=25" + }, + "peerDependenciesMeta": { + "eslint-plugin-jest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-playwright/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-playwright/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint-scope": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", @@ -18017,37 +18251,41 @@ } }, "node_modules/jsdom": { - "version": "26.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", - "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", + "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", + "dev": true, "license": "MIT", "dependencies": { - "cssstyle": "^4.2.1", - "data-urls": "^5.0.0", - "decimal.js": "^10.5.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", + "abab": "^2.0.6", + "cssstyle": "^3.0.0", + "data-urls": "^4.0.0", + "decimal.js": "^10.4.3", + "domexception": "^4.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.16", - "parse5": "^7.2.1", - "rrweb-cssom": "^0.8.0", + "nwsapi": "^2.2.4", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^5.1.1", - "w3c-xmlserializer": "^5.0.0", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.1.1", - "ws": "^8.18.0", - "xml-name-validator": "^5.0.0" + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", + "xml-name-validator": "^4.0.0" }, "engines": { - "node": ">=18" + "node": ">=16" }, "peerDependencies": { - "canvas": "^3.0.0" + "canvas": "^2.5.0" }, "peerDependenciesMeta": { "canvas": { @@ -18055,22 +18293,81 @@ } } }, - "node_modules/jsdom/node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "node_modules/jsdom/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, "license": "MIT", "dependencies": { - "whatwg-encoding": "^3.1.1" + "debug": "4" }, "engines": { - "node": ">=18" + "node": ">= 6.0.0" + } + }, + "node_modules/jsdom/node_modules/cssstyle": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/jsdom/node_modules/data-urls": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", + "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/jsdom/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" } }, "node_modules/jsdom/node_modules/parse5": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "dev": true, "license": "MIT", "dependencies": { "entities": "^4.5.0" @@ -18079,16 +18376,97 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/jsdom/node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "license": "MIT", + "node_modules/jsdom/node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsdom/node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "iconv-lite": "0.6.3" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" }, "engines": { - "node": ">=18" + "node": ">=6" + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/jsdom/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/jsdom/node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/jsdom/node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", + "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/jsdom/node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" } }, "node_modules/jsesc": { @@ -20962,6 +21340,53 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/playwright": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz", + "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.52.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz", + "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/plumb": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/plumb/-/plumb-0.1.0.tgz", @@ -21813,6 +22238,19 @@ "license": "MIT", "optional": true }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, "node_modules/pump": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", @@ -21871,6 +22309,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -24623,6 +25068,20 @@ "express": ">=4.0.0 || >=5.0.0-beta" } }, + "node_modules/swc-loader": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/swc-loader/-/swc-loader-0.1.15.tgz", + "integrity": "sha512-cn1WPIeQJvXM4bbo3OwdEIapsQ4uUGOfyFj0h2+2+brT0k76DCGnZXDE2KmcqTd2JSQ+b61z2NPMib7eEwMYYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0" + }, + "peerDependencies": { + "@swc/core": "^1.2.52", + "webpack": ">=2" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -25270,7 +25729,7 @@ "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -25501,6 +25960,17 @@ "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", "license": "MIT" }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/use-callback-ref": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", @@ -26373,6 +26843,7 @@ "version": "5.98.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", + "dev": true, "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", @@ -26761,6 +27232,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -26774,6 +27246,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" diff --git a/package.json b/package.json index 6a0e9949f..10a9efde5 100644 --- a/package.json +++ b/package.json @@ -9,15 +9,18 @@ "private": true, "devDependencies": { "@eslint/js": "^9.8.0", + "@nx/devkit": "20.8.0", "@nx/esbuild": "20.8.0", "@nx/eslint": "20.8.0", "@nx/eslint-plugin": "20.8.0", "@nx/express": "20.8.0", "@nx/js": "20.8.0", "@nx/node": "20.8.0", + "@nx/playwright": "20.8.0", "@nx/vite": "20.8.0", "@nx/web": "20.8.0", "@nx/webpack": "20.8.0", + "@playwright/test": "^1.36.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.7", "@svgr/webpack": "^8.0.1", "@swc-node/register": "~1.9.1", @@ -31,10 +34,13 @@ "esbuild": "^0.19.2", "eslint": "^9.8.0", "eslint-config-prettier": "^10.0.0", + "eslint-plugin-playwright": "^1.6.2", "jiti": "2.4.2", + "jsdom": "~22.1.0", "jsonc-eslint-parser": "^2.1.0", "nx": "20.8.0", "react-refresh": "^0.10.0", + "swc-loader": "0.1.15", "tslib": "^2.3.0", "typescript": "~5.7.2", "typescript-eslint": "^8.19.0", diff --git a/tsconfig.json b/tsconfig.json index 5fdc35592..bee892ca8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,6 +14,12 @@ }, { "path": "./packages/turndown-plugin-gfm" + }, + { + "path": "./apps/client-e2e" + }, + { + "path": "./apps/client" } ] }