xpine 0.0.21 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/TODO +0 -2
  2. package/dist/index.js +184 -80
  3. package/dist/src/build/esbuild/addDotJS.d.ts +5 -0
  4. package/dist/src/build/esbuild/addDotJS.d.ts.map +1 -0
  5. package/dist/src/build/esbuild/getDataFiles.d.ts +5 -0
  6. package/dist/src/build/esbuild/getDataFiles.d.ts.map +1 -0
  7. package/dist/src/build/esbuild/transformTSXFiles.d.ts +6 -0
  8. package/dist/src/build/esbuild/transformTSXFiles.d.ts.map +1 -0
  9. package/dist/src/express.d.ts +3 -0
  10. package/dist/src/express.d.ts.map +1 -1
  11. package/dist/src/runDevServer.d.ts.map +1 -1
  12. package/dist/src/scripts/build.d.ts +5 -1
  13. package/dist/src/scripts/build.d.ts.map +1 -1
  14. package/dist/src/scripts/xpine-build.js +110 -65
  15. package/dist/src/scripts/xpine-dev.js +148 -68
  16. package/dist/src/static/spa.js +2 -1
  17. package/dist/src/util/config-file.d.ts +6 -0
  18. package/dist/src/util/config-file.d.ts.map +1 -0
  19. package/dist/src/util/constants.d.ts +3 -0
  20. package/dist/src/util/constants.d.ts.map +1 -0
  21. package/dist/src/util/get-config.d.ts.map +1 -1
  22. package/dist/src/util/postcss/remove-layers.d.ts +1 -1
  23. package/dist/src/util/regex.d.ts +11 -0
  24. package/dist/src/util/regex.d.ts.map +1 -0
  25. package/dist/src/util/require.d.ts.map +1 -1
  26. package/dist/types.d.ts +31 -2
  27. package/dist/types.d.ts.map +1 -1
  28. package/eslint.config.mjs +27 -0
  29. package/package.json +18 -4
  30. package/tests/e2e/alpine.spec.ts +14 -0
  31. package/tests/e2e/app-build.spec.ts +73 -0
  32. package/tests/e2e/spa.spec.ts +23 -0
  33. package/tests/e2e/tests-examples/demo-todo-app.spec.ts +437 -0
  34. package/tests/eslint.config.mjs +27 -0
  35. package/tests/package-lock.json +8941 -0
  36. package/tests/package.json +89 -0
  37. package/tests/playwright.config.ts +81 -0
  38. package/tests/tsconfig.json +46 -0
  39. package/tests/xpine.config.mjs +1 -0
  40. package/types.ts +34 -2
@@ -1 +1 @@
1
- {"version":3,"file":"require.d.ts","sourceRoot":"","sources":["../../../src/util/require.ts"],"names":[],"mappings":";AAEA,wBAA8C;AAE9C,wBAAgB,eAAe,WAI9B"}
1
+ {"version":3,"file":"require.d.ts","sourceRoot":"","sources":["../../../src/util/require.ts"],"names":[],"mappings":";AAEA,wBAA8C;AAE9C,wBAAgB,eAAe,WAS9B"}
package/dist/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { Request } from 'express';
1
+ import { Request, Response } from 'express';
2
2
  export type XPineConfig = {
3
- [key: string]: string;
3
+ [key: string]: any;
4
4
  };
5
5
  export type TokenUser = {
6
6
  email?: string;
@@ -8,5 +8,34 @@ export type TokenUser = {
8
8
  };
9
9
  export type ServerRequest = Request & {
10
10
  user?: TokenUser;
11
+ clientIp?: string;
12
+ };
13
+ export type WrapperProps = {
14
+ req: ServerRequest;
15
+ children: any;
16
+ config: ConfigFile;
17
+ data?: any;
18
+ };
19
+ export type ConfigFile = {
20
+ staticPaths?: boolean | (() => Promise<{
21
+ [key: string]: string;
22
+ }[]>);
23
+ wrapper?: (props: WrapperProps) => Promise<any>;
24
+ data?: (req: ServerRequest) => Promise<any>;
25
+ };
26
+ export type PageProps = {
27
+ req: ServerRequest;
28
+ res: Response;
29
+ data: any;
30
+ };
31
+ export type FileItem = {
32
+ file: string;
33
+ size: number;
34
+ };
35
+ export type ComponentData = {
36
+ path: string;
37
+ contents: string;
38
+ clientContent: string;
39
+ configFiles: string[];
11
40
  };
12
41
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG;IACpC,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG;IACpC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,aAAa,CAAC;IACnB,QAAQ,EAAE,GAAG,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,WAAW,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAC,EAAE,CAAC,CAAC,CAAC;IACpE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;CAC7C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,aAAa,CAAC;IACnB,GAAG,EAAE,QAAQ,CAAC;IACd,IAAI,EAAE,GAAG,CAAC;CACX,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAAA"}
@@ -0,0 +1,27 @@
1
+ import eslint from '@eslint/js';
2
+ import tseslint from 'typescript-eslint';
3
+
4
+ export default tseslint.config(
5
+ eslint.configs.recommended,
6
+ tseslint.configs.recommended,
7
+ {
8
+ rules: {
9
+ 'eol-last': 2,
10
+ 'quotes': ['error', 'single'],
11
+ 'comma-dangle': ['error', {
12
+ 'objects': 'always',
13
+ 'arrays': 'never',
14
+ 'imports': 'never',
15
+ 'exports': 'never',
16
+ 'functions': 'never',
17
+ }],
18
+ 'semi': 'error',
19
+ '@typescript-eslint/ban-ts-comment': 'off',
20
+ '@typescript-eslint/no-require-imports': 'off',
21
+ },
22
+ files: ["src/**/*.{js,mjs,ts,tsx,jsx}"],
23
+ },
24
+ {
25
+ ignores: ["dist/", "cdk.out/", "tests/dist/", "tests/playwright-report/"]
26
+ }
27
+ )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xpine",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "main": "dist/index.js",
5
5
  "dependencies": {
6
6
  "@aws-sdk/client-secrets-manager": "^3.758.0",
@@ -16,8 +16,10 @@
16
16
  "jsonwebtoken": "^9.0.2",
17
17
  "postcss": "^8.5.3",
18
18
  "request-ip": "^3.3.0",
19
+ "shelljs": "^0.9.2",
19
20
  "tsx": "^4.19.3",
20
- "typescript": "^5.7.3"
21
+ "typescript": "^5.7.3",
22
+ "yargs": "^17.7.2"
21
23
  },
22
24
  "repository": {
23
25
  "type": "git",
@@ -26,7 +28,14 @@
26
28
  "scripts": {
27
29
  "build": "tsx ./src/scripts/run-build-module.ts && npm run build:types",
28
30
  "build:types": "sh ./src/scripts/build-types.sh",
29
- "xpine-dev-server": "tsx ./src/scripts/xpine-dev-server.ts"
31
+ "xpine-dev-server": "tsx ./src/scripts/xpine-dev-server.ts",
32
+ "test": "cd ./tests && npm run test",
33
+ "test:dev": "cd ./tests && npm run dev",
34
+ "test:start": "cd ./tests && npm run build && npm start",
35
+ "test:build": "cd ./tests && npm run build",
36
+ "lint": "npx eslint",
37
+ "fix": "npx eslint --fix",
38
+ "publish": "npm run build && npm version patch && npm publish"
30
39
  },
31
40
  "bin": {
32
41
  "xpine-build": "dist/src/scripts/xpine-build.js",
@@ -35,8 +44,13 @@
35
44
  "types": "dist/index.d.ts",
36
45
  "type": "module",
37
46
  "devDependencies": {
47
+ "@eslint/js": "^9.24.0",
38
48
  "@types/express": "^5.0.0",
39
49
  "@types/node": "^22.13.5",
40
- "@types/request-ip": "^0.0.41"
50
+ "@types/request-ip": "^0.0.41",
51
+ "@types/shelljs": "^0.8.15",
52
+ "@types/yargs": "^17.0.33",
53
+ "axios": "^1.8.4",
54
+ "typescript-eslint": "^8.29.0"
41
55
  }
42
56
  }
@@ -0,0 +1,14 @@
1
+ import { test, expect } from '@playwright/test';
2
+ import { url } from '../playwright.config';
3
+
4
+ test('pathD button changes color on button click', async ({ page }) => {
5
+ await page.goto(url + '/my-path-a2/my-path-b2/my-path-c2/2');
6
+ const button = page.getByTestId('path-d-button');
7
+ const initialStyle = await button.getAttribute('style');
8
+ expect(initialStyle).toEqual('background-color: red');
9
+ await test.step('click button', async () => {
10
+ await button.click();
11
+ const newStyle = await button.getAttribute('style');
12
+ expect(newStyle).toEqual('background-color: blue');
13
+ });
14
+ });
@@ -0,0 +1,73 @@
1
+ import { test, expect } from '@playwright/test';
2
+ import { config } from 'xpine';
3
+ import fs from 'fs-extra';
4
+ import path from 'path';
5
+ import { url } from '../playwright.config';
6
+
7
+ test('app builds', async ({ page }) => {
8
+ await page.goto(url);
9
+ await expect(page.getByTestId('hello-world')).toHaveText('Hello world');
10
+ });
11
+
12
+ test('home page uses same file wrapper', async ({ page }) => {
13
+ await page.goto(url);
14
+ await expect(page.getByTestId('home-page-wrapper')).toBeAttached();
15
+ expect(await page.getByTestId('base-config').count()).toEqual(0);
16
+ const title = await page.title();
17
+ expect(title).toEqual('Home page');
18
+ });
19
+
20
+ test('same dir +config uses config', async ({ page }) => {
21
+ await page.goto(url + '/with-same-dir-wrapper');
22
+ await expect(page.getByTestId('base-config')).toBeAttached();
23
+ const title = await page.title();
24
+ expect(title).toEqual('Default title');
25
+ });
26
+
27
+ test('dynamic paths with data in +config - path c', async ({ page }) => {
28
+ const result = await page.goto(url + '/my-path-a/my-path-b/1');
29
+ await expect(page.getByTestId('path-c-data')).toHaveText('sunt aut facere repellat provident occaecati excepturi optio reprehenderit');
30
+ await expect(page.getByTestId('path-c-patha')).toHaveText('my-path-a');
31
+ await expect(page.getByTestId('path-c-pathb')).toHaveText('my-path-b');
32
+ await expect(page.getByTestId('base-config')).toBeAttached();
33
+ const body = (await result.body()).toString();
34
+ expect(body).toContain('<!-- static -->');
35
+ });
36
+
37
+ test('dynamic inner paths with config in the component - path d', async ({ page }) => {
38
+ const result = await page.goto(url + '/my-path-a2/my-path-b2/my-path-c2/2');
39
+ await expect(page.getByTestId('path-d-data')).toHaveText('qui est esse');
40
+ await expect(page.getByTestId('path-d-patha')).toHaveText('my-path-a2');
41
+ await expect(page.getByTestId('path-d-pathb')).toHaveText('my-path-b2');
42
+ await expect(page.getByTestId('path-d-pathc')).toHaveText('my-path-c2');
43
+ await expect(page.getByTestId('base-config')).toBeAttached();
44
+ const body = (await result.body()).toString();
45
+ expect(body).toContain('<!-- static -->');
46
+ });
47
+
48
+ test('static paths exist for dynamic page', async () => {
49
+ expect(fs.existsSync(path.join(config.distDir, './pages/my-path-a2/my-path-b2/my-path-c2/2/index.html'))).toEqual(true);
50
+ });
51
+
52
+ test('boolean static path', async ({ page }) => {
53
+ const result = await page.goto(url + '/boolean-static-path');
54
+ const body = (await result.body()).toString();
55
+ expect(body).toContain('<!-- static -->');
56
+
57
+ expect(fs.existsSync(path.join(config.distDir, './pages/boolean-static-path/index.html'))).toEqual(true);
58
+ });
59
+
60
+ test('inner static path override', async ({ page }) => {
61
+ expect(fs.existsSync(path.join(config.distDir, './pages/base-static-path/index.html'))).toEqual(true);
62
+ expect(fs.existsSync(path.join(config.distDir, './pages/base-static-path/non-static-path/index.html'))).toEqual(false);
63
+
64
+ const staticResult = await page.goto(url + '/base-static-path');
65
+ await expect(page.getByTestId('base-static-path')).toHaveText('My title');
66
+ const staticBody = (await staticResult.body()).toString();
67
+ expect(staticBody).toContain('<!-- static -->');
68
+
69
+ const nonStaticResult = await page.goto(url + '/base-static-path/non-static-path');
70
+ await expect(page.getByTestId('non-static-path')).toHaveText('My title');
71
+ const nonStaticBody = (await nonStaticResult.body()).toString();
72
+ expect(nonStaticBody).not.toContain('<!-- static -->');
73
+ });
@@ -0,0 +1,23 @@
1
+ import { test, expect } from '@playwright/test';
2
+ import { url } from '../playwright.config';
3
+
4
+
5
+ test('sticky nav creates request for page contents and does not reload page', async ({ page }) => {
6
+ await page.goto(url);
7
+ const link = page.getByTestId('navbar-boolean-static-path');
8
+ const navbarNow = await page.getByTestId('navbar-now').getAttribute('data-now');
9
+ await link.click();
10
+ await page.waitForURL('**/boolean-static-path');
11
+ const newNavbarNow = await page.getByTestId('navbar-now').getAttribute('data-now');
12
+ expect(navbarNow).toEqual(newNavbarNow);
13
+ });
14
+
15
+ test('non-spa request for page contents reloads page', async ({ page }) => {
16
+ await page.goto(url);
17
+ const link = page.getByTestId('navbar-non-static-path-non-spa');
18
+ const navbarNow = await page.getByTestId('navbar-now').getAttribute('data-now');
19
+ await link.click();
20
+ await page.waitForURL('**/base-static-path/non-static-path');
21
+ const newNavbarNow = await page.getByTestId('navbar-now').getAttribute('data-now');
22
+ expect(navbarNow).not.toEqual(newNavbarNow);
23
+ });