htmv 0.0.34 → 0.0.36
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/next-parser/renderer.js +11 -2
- package/package.json +13 -2
- package/.github/workflows/ci.yml +0 -27
- package/.github/workflows/publish.yml +0 -42
- package/bun.lock +0 -98
- package/src/app.ts +0 -10
- package/src/cli/cli.ts +0 -28
- package/src/cli/commands/gen.ts +0 -87
- package/src/cli/commands/help.ts +0 -5
- package/src/cli/commands/new.ts +0 -83
- package/src/cli/consts.ts +0 -2
- package/src/cli/utils.ts +0 -10
- package/src/index.ts +0 -17
- package/src/next-parser/parser.ts +0 -113
- package/src/next-parser/renderer.ts +0 -81
- package/src/next-parser/tokenizer.ts +0 -123
- package/src/routing.ts +0 -43
- package/src/types.ts +0 -16
- package/src/views.ts +0 -26
- package/tsconfig.json +0 -32
|
@@ -18,8 +18,11 @@ export function render(node, context) {
|
|
|
18
18
|
return String(resolvePropertyPath(node.value));
|
|
19
19
|
}
|
|
20
20
|
if (node.type === "isset") {
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const isNegated = node.itemName.startsWith("!");
|
|
22
|
+
const propName = isNegated ? node.itemName.slice(1) : node.itemName;
|
|
23
|
+
const prop = resolvePropertyPath(propName);
|
|
24
|
+
const exists = isset(prop);
|
|
25
|
+
if (isNegated ? !exists : exists) {
|
|
23
26
|
return node.children.map((node) => render(node, context)).join("");
|
|
24
27
|
}
|
|
25
28
|
return "";
|
|
@@ -39,3 +42,9 @@ export function render(node, context) {
|
|
|
39
42
|
return result;
|
|
40
43
|
}
|
|
41
44
|
}
|
|
45
|
+
function isset(prop) {
|
|
46
|
+
if (Array.isArray(prop)) {
|
|
47
|
+
return prop.length > 0;
|
|
48
|
+
}
|
|
49
|
+
return prop !== undefined && prop !== null && prop !== false;
|
|
50
|
+
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "htmv",
|
|
3
3
|
"main": "dist/index.js",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.36",
|
|
6
6
|
"devDependencies": {
|
|
7
7
|
"@biomejs/biome": "2.3.3",
|
|
8
8
|
"@types/bun": "latest"
|
|
@@ -26,5 +26,16 @@
|
|
|
26
26
|
"repository": {
|
|
27
27
|
"type": "git",
|
|
28
28
|
"url": "https://github.com/Fabrisdev/htmv"
|
|
29
|
-
}
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"framework",
|
|
32
|
+
"web-framework",
|
|
33
|
+
"web",
|
|
34
|
+
"server",
|
|
35
|
+
"backend",
|
|
36
|
+
"frontend",
|
|
37
|
+
"cli"
|
|
38
|
+
],
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"description": "A simple yet fast web framework"
|
|
30
41
|
}
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [ main ]
|
|
6
|
-
pull_request:
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
build:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
|
|
12
|
-
steps:
|
|
13
|
-
- uses: actions/checkout@v4
|
|
14
|
-
|
|
15
|
-
- name: Setup Bun
|
|
16
|
-
uses: oven-sh/setup-bun@v1
|
|
17
|
-
with:
|
|
18
|
-
bun-version: latest
|
|
19
|
-
|
|
20
|
-
- name: Install dependencies
|
|
21
|
-
run: bun install
|
|
22
|
-
|
|
23
|
-
- name: Lint
|
|
24
|
-
run: npm run lint
|
|
25
|
-
|
|
26
|
-
- name: Run TypeScript build
|
|
27
|
-
run: npm run build
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
name: Publish to npm
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- "v*"
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
id-token: write # Required for OIDC
|
|
10
|
-
contents: read
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
publish:
|
|
14
|
-
runs-on: ubuntu-latest
|
|
15
|
-
|
|
16
|
-
steps:
|
|
17
|
-
- uses: actions/checkout@v4
|
|
18
|
-
|
|
19
|
-
- uses: actions/setup-node@v4
|
|
20
|
-
with:
|
|
21
|
-
node-version: '20'
|
|
22
|
-
registry-url: 'https://registry.npmjs.org'
|
|
23
|
-
|
|
24
|
-
- name: Update npm
|
|
25
|
-
run: npm install -g npm@latest
|
|
26
|
-
|
|
27
|
-
- name: Setup Bun
|
|
28
|
-
uses: oven-sh/setup-bun@v1
|
|
29
|
-
with:
|
|
30
|
-
bun-version: latest
|
|
31
|
-
|
|
32
|
-
- name: Install dependencies
|
|
33
|
-
run: bun install
|
|
34
|
-
|
|
35
|
-
- name: Lint
|
|
36
|
-
run: npm run lint
|
|
37
|
-
|
|
38
|
-
- name: Build (tsc)
|
|
39
|
-
run: npm run build
|
|
40
|
-
|
|
41
|
-
- name: Publish to npm
|
|
42
|
-
run: npm publish --provenance
|
package/bun.lock
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"lockfileVersion": 1,
|
|
3
|
-
"configVersion": 0,
|
|
4
|
-
"workspaces": {
|
|
5
|
-
"": {
|
|
6
|
-
"name": "htmv",
|
|
7
|
-
"dependencies": {
|
|
8
|
-
"@elysiajs/node": "^1.4.2",
|
|
9
|
-
"@elysiajs/static": "^1.4.6",
|
|
10
|
-
"elysia": "^1.4.18",
|
|
11
|
-
},
|
|
12
|
-
"devDependencies": {
|
|
13
|
-
"@biomejs/biome": "2.3.3",
|
|
14
|
-
"@types/bun": "latest",
|
|
15
|
-
},
|
|
16
|
-
"peerDependencies": {
|
|
17
|
-
"typescript": "^5",
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
"packages": {
|
|
22
|
-
"@biomejs/biome": ["@biomejs/biome@2.3.3", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.3", "@biomejs/cli-darwin-x64": "2.3.3", "@biomejs/cli-linux-arm64": "2.3.3", "@biomejs/cli-linux-arm64-musl": "2.3.3", "@biomejs/cli-linux-x64": "2.3.3", "@biomejs/cli-linux-x64-musl": "2.3.3", "@biomejs/cli-win32-arm64": "2.3.3", "@biomejs/cli-win32-x64": "2.3.3" }, "bin": { "biome": "bin/biome" } }, "sha512-zn/P1pRBCpDdhi+VNSMnpczOz9DnqzOA2c48K8xgxjDODvi5O8gs3a2H233rck/5HXpkFj6TmyoqVvxirZUnvg=="],
|
|
23
|
-
|
|
24
|
-
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5+JtW6RKmjqL9un0UtHV0ezOslAyYBzyl5ZhYiu7GHesX2x8NCDl6tXYrenv9m7e1RLbkO5E5Kh04kseMtz6lw=="],
|
|
25
|
-
|
|
26
|
-
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-UPmKRalkHicvIpeccuKqq+/gA2HYV8FUnAEDJnqYBlGlycKqe6xrovWqvWTE4TTNpIFf4UQyuaDzLkN6Kz6tbA=="],
|
|
27
|
-
|
|
28
|
-
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-zeiKwALNB/hax7+LLhCYqhqzlWdTfgE9BGkX2Z8S4VmCYnGFrf2fON/ec6KCos7mra5MDm6fYICsEWN2+HKZhw=="],
|
|
29
|
-
|
|
30
|
-
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-KhCDMV+V7Yu72v40ssGJTHuv/j0n7JQ6l0s/c+EMcX5zPYLMLr4XpmI+WXhp4Vfkz0T5Xnh5wbrTBI3f2UTpjQ=="],
|
|
31
|
-
|
|
32
|
-
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-05CjPLbvVVU8J6eaO6iSEoA0FXKy2l6ddL+1h/VpiosCmIp3HxRKLOa1hhC1n+D13Z8g9b1DtnglGtM5U3sTag=="],
|
|
33
|
-
|
|
34
|
-
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-IyqQ+jYzU5MVy9CK5NV0U+NnUMPUAhYMrB/x4QgL/Dl1MqzBVc61bHeyhLnKM6DSEk73/TQYrk/8/QmVHudLdQ=="],
|
|
35
|
-
|
|
36
|
-
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-NtlLs3pdFqFAQYZjlEHKOwJEn3GEaz7rtR2oCrzaLT2Xt3Cfd55/VvodQ5V+X+KepLa956QJagckJrNL+DmumQ=="],
|
|
37
|
-
|
|
38
|
-
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-klJKPPQvUk9Rlp0Dd56gQw/+Wt6uUprHdHWtbDC93f3Iv+knA2tLWpcYoOZJgPV+9s+RBmYv0DGy4mUlr20esg=="],
|
|
39
|
-
|
|
40
|
-
"@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="],
|
|
41
|
-
|
|
42
|
-
"@elysiajs/node": ["@elysiajs/node@1.4.2", "", { "dependencies": { "crossws": "^0.4.1", "srvx": "^0.9.4" }, "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-zqeBAV4/faCcmIEjCp3g6jRwsbaWsd5HqmlEf3CirD9HkTWQNo4T+GN/qGZi7zgd84D3Kzxsny7ZTMXEfrDSXQ=="],
|
|
43
|
-
|
|
44
|
-
"@elysiajs/static": ["@elysiajs/static@1.4.6", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-cd61aY/DHOVhlnBjzTBX8E1XANIrsCH8MwEGHeLMaZzNrz0gD4Q8Qsde2dFMzu81I7ZDaaZ2Rim9blSLtUrYBg=="],
|
|
45
|
-
|
|
46
|
-
"@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="],
|
|
47
|
-
|
|
48
|
-
"@tokenizer/inflate": ["@tokenizer/inflate@0.2.7", "", { "dependencies": { "debug": "^4.4.0", "fflate": "^0.8.2", "token-types": "^6.0.0" } }, "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg=="],
|
|
49
|
-
|
|
50
|
-
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
|
|
51
|
-
|
|
52
|
-
"@types/bun": ["@types/bun@1.3.1", "", { "dependencies": { "bun-types": "1.3.1" } }, "sha512-4jNMk2/K9YJtfqwoAa28c8wK+T7nvJFOjxI4h/7sORWcypRNxBpr+TPNaCfVWq70tLCJsqoFwcf0oI0JU/fvMQ=="],
|
|
53
|
-
|
|
54
|
-
"@types/node": ["@types/node@24.10.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A=="],
|
|
55
|
-
|
|
56
|
-
"@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
|
|
57
|
-
|
|
58
|
-
"bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="],
|
|
59
|
-
|
|
60
|
-
"cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
|
|
61
|
-
|
|
62
|
-
"crossws": ["crossws@0.4.1", "", { "peerDependencies": { "srvx": ">=0.7.1" }, "optionalPeers": ["srvx"] }, "sha512-E7WKBcHVhAVrY6JYD5kteNqVq1GSZxqGrdSiwXR9at+XHi43HJoCQKXcCczR5LBnBquFZPsB3o7HklulKoBU5w=="],
|
|
63
|
-
|
|
64
|
-
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
|
65
|
-
|
|
66
|
-
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
|
67
|
-
|
|
68
|
-
"elysia": ["elysia@1.4.18", "", { "dependencies": { "cookie": "^1.1.1", "exact-mirror": "0.2.5", "fast-decode-uri-component": "^1.0.1", "memoirist": "^0.4.0" }, "peerDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "@types/bun": ">= 1.2.0", "file-type": ">= 20.0.0", "openapi-types": ">= 12.0.0", "typescript": ">= 5.0.0" }, "optionalPeers": ["@types/bun", "typescript"] }, "sha512-A6BhlipmSvgCy69SBgWADYZSdDIj3fT2gk8/9iMAC8iD+aGcnCr0fitziX0xr36MFDs/fsvVp8dWqxeq1VCgKg=="],
|
|
69
|
-
|
|
70
|
-
"exact-mirror": ["exact-mirror@0.2.5", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-u8Wu2lO8nio5lKSJubOydsdNtQmH8ENba5m0nbQYmTvsjksXKYIS1nSShdDlO8Uem+kbo+N6eD5I03cpZ+QsRQ=="],
|
|
71
|
-
|
|
72
|
-
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
|
|
73
|
-
|
|
74
|
-
"fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="],
|
|
75
|
-
|
|
76
|
-
"file-type": ["file-type@21.0.0", "", { "dependencies": { "@tokenizer/inflate": "^0.2.7", "strtok3": "^10.2.2", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" } }, "sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg=="],
|
|
77
|
-
|
|
78
|
-
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
|
|
79
|
-
|
|
80
|
-
"memoirist": ["memoirist@0.4.0", "", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="],
|
|
81
|
-
|
|
82
|
-
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
|
83
|
-
|
|
84
|
-
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
|
|
85
|
-
|
|
86
|
-
"srvx": ["srvx@0.9.5", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-nQsA2c8q3XwbSn6kTxVQjz0zS096rV+Be2pzJwrYEAdtnYszLw4MTy8JWJjz1XEGBZwP0qW51SUIX3WdjdRemQ=="],
|
|
87
|
-
|
|
88
|
-
"strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="],
|
|
89
|
-
|
|
90
|
-
"token-types": ["token-types@6.1.1", "", { "dependencies": { "@borewit/text-codec": "^0.1.0", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ=="],
|
|
91
|
-
|
|
92
|
-
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
|
93
|
-
|
|
94
|
-
"uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="],
|
|
95
|
-
|
|
96
|
-
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
|
97
|
-
}
|
|
98
|
-
}
|
package/src/app.ts
DELETED
package/src/cli/cli.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import gen from "./commands/gen.js";
|
|
3
|
-
import help from "./commands/help.js";
|
|
4
|
-
import newCommand from "./commands/new.js";
|
|
5
|
-
import { AVAILABLE_COMMANDS } from "./consts.js";
|
|
6
|
-
|
|
7
|
-
const args = process.argv.slice(2);
|
|
8
|
-
const command = args[0];
|
|
9
|
-
if (command === undefined) {
|
|
10
|
-
console.error("No command specified. Available commands are:");
|
|
11
|
-
console.error(AVAILABLE_COMMANDS);
|
|
12
|
-
process.exit(1);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const commandArgs = args.slice(1);
|
|
16
|
-
const commands = {
|
|
17
|
-
help,
|
|
18
|
-
new: () => newCommand(commandArgs),
|
|
19
|
-
gen: () => gen(commandArgs),
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
if (command in commands) {
|
|
23
|
-
await commands[command as keyof typeof commands]();
|
|
24
|
-
process.exit(0);
|
|
25
|
-
}
|
|
26
|
-
console.error("Unknown command. Available commands are:");
|
|
27
|
-
console.error(AVAILABLE_COMMANDS);
|
|
28
|
-
process.exit(1);
|
package/src/cli/commands/gen.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { exists } from "../utils.js";
|
|
4
|
-
|
|
5
|
-
export default async (args: string[]) => {
|
|
6
|
-
const [type, name, ...options] = args;
|
|
7
|
-
if (type === undefined || name === undefined)
|
|
8
|
-
return console.error(
|
|
9
|
-
"You must specify both a type and name of file to generate.\nCorrect usage: htmv gen {TYPE} {NAME} {OPTIONS}",
|
|
10
|
-
);
|
|
11
|
-
if (!["view", "route"].includes(type.toLowerCase()))
|
|
12
|
-
return console.error("Invalid type inputted. Valid types are: view, route");
|
|
13
|
-
if (type.toLowerCase() === "view") {
|
|
14
|
-
const viewsFolderPath = await validateOptions("views", ...options);
|
|
15
|
-
const viewsContents = `<!DOCTYPE html>
|
|
16
|
-
<html lang="en">
|
|
17
|
-
|
|
18
|
-
<head>
|
|
19
|
-
<title>${name} view</title>
|
|
20
|
-
</head>
|
|
21
|
-
|
|
22
|
-
<body>
|
|
23
|
-
<h1>This view was quickly generated with htmv gen.</h1>
|
|
24
|
-
</body>
|
|
25
|
-
</html>`;
|
|
26
|
-
const fileName = `${name}.html`;
|
|
27
|
-
const filePath = path.join(viewsFolderPath, fileName);
|
|
28
|
-
const fileAlreadyExists = await exists(filePath);
|
|
29
|
-
if (fileAlreadyExists)
|
|
30
|
-
return console.error(`File ${fileName} already exists.`);
|
|
31
|
-
await generateFile(filePath, viewsContents);
|
|
32
|
-
}
|
|
33
|
-
if (type.toLowerCase() === "route") {
|
|
34
|
-
const routesFolderPath = await validateOptions("routes", ...options);
|
|
35
|
-
const routeContents = `import { type RouteParams } from "htmv";
|
|
36
|
-
|
|
37
|
-
export default (_params: RouteParams) => {
|
|
38
|
-
return "Just a simple ALL method.";
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export function POST (_params: RouteParams) {
|
|
42
|
-
return "Searching for something more specific? How about a POST method route?"
|
|
43
|
-
};
|
|
44
|
-
`;
|
|
45
|
-
const fileName = `${name}.ts`;
|
|
46
|
-
const filePath = path.join(routesFolderPath, fileName);
|
|
47
|
-
const fileAlreadyExists = await exists(filePath);
|
|
48
|
-
|
|
49
|
-
if (fileAlreadyExists)
|
|
50
|
-
return console.error(`File ${fileName} already exists.`);
|
|
51
|
-
await generateFile(filePath, routeContents);
|
|
52
|
-
}
|
|
53
|
-
console.log(`${type} ${name} generated succesfully.`);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
async function generateFile(_path: string, contents: string) {
|
|
57
|
-
await fs.writeFile(_path, contents);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async function validateOptions(
|
|
61
|
-
folderName: string,
|
|
62
|
-
optionName?: string,
|
|
63
|
-
optionValue?: string,
|
|
64
|
-
) {
|
|
65
|
-
let folderPath = path.resolve(folderName);
|
|
66
|
-
if (optionName) {
|
|
67
|
-
if (optionName !== "--path") {
|
|
68
|
-
console.error("Invalid option provided. Valid options are: --path.");
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (optionValue === undefined) {
|
|
73
|
-
console.error("No option value provided.");
|
|
74
|
-
process.exit(1);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
folderPath = path.resolve(optionValue);
|
|
78
|
-
}
|
|
79
|
-
const viewsFolderExists = await exists(folderPath);
|
|
80
|
-
if (!viewsFolderExists) {
|
|
81
|
-
console.error(
|
|
82
|
-
`Unable to find ${folderName} folder. Did you change your ${folderName} folder's name? If so, did you pass the option --path with the corresponding path to it?`,
|
|
83
|
-
);
|
|
84
|
-
process.exit(1);
|
|
85
|
-
}
|
|
86
|
-
return folderPath;
|
|
87
|
-
}
|
package/src/cli/commands/help.ts
DELETED
package/src/cli/commands/new.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import childProcess from "node:child_process";
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { exists } from "../utils.js";
|
|
5
|
-
|
|
6
|
-
export default async (args: string[]) => {
|
|
7
|
-
const name = args[0];
|
|
8
|
-
if (name === undefined)
|
|
9
|
-
return console.error("No name supplied. Project creation cancelled");
|
|
10
|
-
console.log("1. Starting project creation...");
|
|
11
|
-
const folderAlreadyExists = await exists(name);
|
|
12
|
-
if (folderAlreadyExists)
|
|
13
|
-
return console.error("There already exists a folder with that name.");
|
|
14
|
-
const fullPath = path.resolve(name);
|
|
15
|
-
await fs.mkdir(name);
|
|
16
|
-
console.log("2. Creating a new bun project...");
|
|
17
|
-
await runCommand("bun init -y", {
|
|
18
|
-
cwd: fullPath,
|
|
19
|
-
});
|
|
20
|
-
console.log("3. Installing dependencies...");
|
|
21
|
-
await runCommand("bun add htmv", {
|
|
22
|
-
cwd: fullPath,
|
|
23
|
-
});
|
|
24
|
-
console.log("4. Scaffolding project structure...");
|
|
25
|
-
await fs.mkdir(path.join(fullPath, "public"));
|
|
26
|
-
await fs.mkdir(path.join(fullPath, "routes"));
|
|
27
|
-
await fs.mkdir(path.join(fullPath, "views"));
|
|
28
|
-
const indexContent = `import path from "node:path";
|
|
29
|
-
import { fileURLToPath } from "node:url";
|
|
30
|
-
import { setup } from "htmv";
|
|
31
|
-
|
|
32
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
33
|
-
const dirPath = path.dirname(__filename);
|
|
34
|
-
setup({
|
|
35
|
-
routes: path.join(dirPath, "routes"),
|
|
36
|
-
views: path.join(dirPath, "views"),
|
|
37
|
-
public: path.join(dirPath, "public"),
|
|
38
|
-
port: 3000,
|
|
39
|
-
});`;
|
|
40
|
-
await fs.writeFile(path.join(fullPath, "index.ts"), indexContent);
|
|
41
|
-
const routeContent = `import { type RouteParams, view } from "htmv";
|
|
42
|
-
|
|
43
|
-
export default async (_params: RouteParams) => {
|
|
44
|
-
return await view("example", {
|
|
45
|
-
title: "Welcome to HTMV!",
|
|
46
|
-
});
|
|
47
|
-
};
|
|
48
|
-
`;
|
|
49
|
-
await fs.writeFile(path.join(fullPath, "routes", "index.ts"), routeContent);
|
|
50
|
-
const viewContent = `<!DOCTYPE html>
|
|
51
|
-
<html lang="en">
|
|
52
|
-
|
|
53
|
-
<head>
|
|
54
|
-
<title>{title}</title>
|
|
55
|
-
</head>
|
|
56
|
-
|
|
57
|
-
<body>
|
|
58
|
-
<h1>{title}</h1>
|
|
59
|
-
</body>
|
|
60
|
-
</html>`;
|
|
61
|
-
await fs.writeFile(path.join(fullPath, "views", "example.html"), viewContent);
|
|
62
|
-
console.log("5. Creating run scripts...");
|
|
63
|
-
await runCommand(`npm pkg set scripts.dev="bun --watch ."`, {
|
|
64
|
-
cwd: fullPath,
|
|
65
|
-
});
|
|
66
|
-
await runCommand(`npm pkg set scripts.start="bun index.ts"`, {
|
|
67
|
-
cwd: fullPath,
|
|
68
|
-
});
|
|
69
|
-
console.log(`All done! Project ${name} created.`);
|
|
70
|
-
console.log(`Now run cd ${name} and start building your next big project!`);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
async function runCommand(
|
|
74
|
-
command: string,
|
|
75
|
-
options?: childProcess.ExecOptionsWithStringEncoding,
|
|
76
|
-
) {
|
|
77
|
-
const process = childProcess.exec(command, options);
|
|
78
|
-
return new Promise((resolve) => {
|
|
79
|
-
process.on("exit", () => {
|
|
80
|
-
resolve(1);
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
}
|
package/src/cli/consts.ts
DELETED
package/src/cli/utils.ts
DELETED
package/src/index.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { createApp } from "./app";
|
|
2
|
-
import { registerRoutes } from "./routing";
|
|
3
|
-
import type { Paths } from "./types";
|
|
4
|
-
import { setViewsPath } from "./views";
|
|
5
|
-
|
|
6
|
-
export type { RouteParams } from "./types";
|
|
7
|
-
export { view } from "./views";
|
|
8
|
-
|
|
9
|
-
export async function setup(paths: Paths) {
|
|
10
|
-
setViewsPath(paths.views);
|
|
11
|
-
const app = createApp(paths.public);
|
|
12
|
-
await registerRoutes(app, paths.routes);
|
|
13
|
-
app.listen(paths.port);
|
|
14
|
-
console.log("");
|
|
15
|
-
console.log(`HTMV running on port ${paths.port}! 🎉`);
|
|
16
|
-
console.log(`http://localhost:${paths.port}`);
|
|
17
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import type { Node, RootNode } from "./renderer";
|
|
2
|
-
import type { Token } from "./tokenizer";
|
|
3
|
-
|
|
4
|
-
export function parse(tokens: Token[]) {
|
|
5
|
-
let i = 0;
|
|
6
|
-
|
|
7
|
-
const root: RootNode = {
|
|
8
|
-
type: "root",
|
|
9
|
-
children: parseChildren(),
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
return root;
|
|
13
|
-
|
|
14
|
-
function parseChildren(untilTag?: string): Node[] {
|
|
15
|
-
const nodes: Node[] = [];
|
|
16
|
-
while (i < tokens.length) {
|
|
17
|
-
const token = tokens[i];
|
|
18
|
-
if (
|
|
19
|
-
untilTag &&
|
|
20
|
-
token?.type === "close" &&
|
|
21
|
-
token.tag.toLocaleLowerCase() === untilTag
|
|
22
|
-
) {
|
|
23
|
-
i++;
|
|
24
|
-
break;
|
|
25
|
-
}
|
|
26
|
-
if (token?.type === "text") {
|
|
27
|
-
nodes.push({
|
|
28
|
-
type: "text",
|
|
29
|
-
text: token.text,
|
|
30
|
-
});
|
|
31
|
-
i++;
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
if (token?.type === "interpolation") {
|
|
35
|
-
nodes.push({
|
|
36
|
-
type: "interpolation",
|
|
37
|
-
value: token.value,
|
|
38
|
-
});
|
|
39
|
-
i++;
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
if (token?.type === "open") {
|
|
43
|
-
const tag = token.tag.toLowerCase();
|
|
44
|
-
i++;
|
|
45
|
-
if (tag === "for") {
|
|
46
|
-
const nextToken = tokens[i]; //should be arguments token
|
|
47
|
-
i++;
|
|
48
|
-
if (nextToken?.type !== "arguments")
|
|
49
|
-
throw new Error("Missing arguments in for");
|
|
50
|
-
const [itemName, _in, listName] = nextToken.value;
|
|
51
|
-
if (
|
|
52
|
-
itemName === undefined ||
|
|
53
|
-
_in === undefined ||
|
|
54
|
-
listName === undefined
|
|
55
|
-
)
|
|
56
|
-
throw new Error(
|
|
57
|
-
"Incorrect amount of arguments in for. Expected 3 arguments",
|
|
58
|
-
);
|
|
59
|
-
if (_in !== "in") throw new Error("Expected reserved word in.");
|
|
60
|
-
|
|
61
|
-
const children = parseChildren(tag);
|
|
62
|
-
nodes.push({
|
|
63
|
-
type: "for",
|
|
64
|
-
children,
|
|
65
|
-
itemName,
|
|
66
|
-
listName,
|
|
67
|
-
});
|
|
68
|
-
continue;
|
|
69
|
-
}
|
|
70
|
-
if (tag === "isset") {
|
|
71
|
-
const nextToken = tokens[i]; //should be arguments token
|
|
72
|
-
i++;
|
|
73
|
-
if (nextToken?.type !== "arguments")
|
|
74
|
-
throw new Error("Missing arguments in isset");
|
|
75
|
-
const [itemName] = nextToken.value;
|
|
76
|
-
if (itemName === undefined) throw new Error("Expected item name");
|
|
77
|
-
const children = parseChildren(tag);
|
|
78
|
-
nodes.push({
|
|
79
|
-
type: "isset",
|
|
80
|
-
children,
|
|
81
|
-
itemName,
|
|
82
|
-
});
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
const nextToken = tokens[i]; //may be arguments token
|
|
86
|
-
if (nextToken?.type === "arguments") {
|
|
87
|
-
const args = nextToken.value.join(" ");
|
|
88
|
-
nodes.push({
|
|
89
|
-
type: "text",
|
|
90
|
-
text: `<${tag} ${args}>`,
|
|
91
|
-
});
|
|
92
|
-
i++;
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
nodes.push({
|
|
96
|
-
type: "text",
|
|
97
|
-
text: `<${tag}>`,
|
|
98
|
-
});
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
if (token?.type === "close") {
|
|
102
|
-
if (token.tag === "for" || token.tag === "isset") continue;
|
|
103
|
-
const tag = token.tag;
|
|
104
|
-
nodes.push({
|
|
105
|
-
type: "text",
|
|
106
|
-
text: `</${tag}>`,
|
|
107
|
-
});
|
|
108
|
-
i++;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return nodes;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
export type Node =
|
|
2
|
-
| RootNode
|
|
3
|
-
| TextNode
|
|
4
|
-
| InterpolationNode
|
|
5
|
-
| IssetNode
|
|
6
|
-
| ForNode;
|
|
7
|
-
|
|
8
|
-
export interface RootNode {
|
|
9
|
-
type: "root";
|
|
10
|
-
children: Node[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface TextNode {
|
|
14
|
-
type: "text";
|
|
15
|
-
text: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface InterpolationNode {
|
|
19
|
-
type: "interpolation";
|
|
20
|
-
value: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface IssetNode {
|
|
24
|
-
type: "isset";
|
|
25
|
-
itemName: string;
|
|
26
|
-
children: Node[];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface ForNode {
|
|
30
|
-
type: "for";
|
|
31
|
-
listName: string;
|
|
32
|
-
itemName: string;
|
|
33
|
-
children: Node[];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function render(node: Node, context: Record<string, unknown>): string {
|
|
37
|
-
if (node.type === "text") {
|
|
38
|
-
return node.text;
|
|
39
|
-
}
|
|
40
|
-
if (node.type === "for") {
|
|
41
|
-
const list = context[node.listName];
|
|
42
|
-
if (Array.isArray(list)) {
|
|
43
|
-
const output = list.map((item) => {
|
|
44
|
-
return node.children
|
|
45
|
-
.map((childrenNode) =>
|
|
46
|
-
render(childrenNode, { ...context, [node.itemName]: item }),
|
|
47
|
-
)
|
|
48
|
-
.join("");
|
|
49
|
-
});
|
|
50
|
-
return output.join("");
|
|
51
|
-
}
|
|
52
|
-
throw new Error("La lista pasada no es un array");
|
|
53
|
-
}
|
|
54
|
-
if (node.type === "interpolation") {
|
|
55
|
-
return String(resolvePropertyPath(node.value));
|
|
56
|
-
}
|
|
57
|
-
if (node.type === "isset") {
|
|
58
|
-
if (
|
|
59
|
-
context[node.itemName] !== undefined &&
|
|
60
|
-
context[node.itemName] !== null
|
|
61
|
-
) {
|
|
62
|
-
return node.children.map((node) => render(node, context)).join("");
|
|
63
|
-
}
|
|
64
|
-
return "";
|
|
65
|
-
}
|
|
66
|
-
const output = node.children.map((node) => render(node, context));
|
|
67
|
-
return output.join("");
|
|
68
|
-
|
|
69
|
-
function resolvePropertyPath(path: string) {
|
|
70
|
-
const [variable, ...properties] = path.split(".");
|
|
71
|
-
if (variable === undefined)
|
|
72
|
-
throw new Error("Missing variable name on interpolation");
|
|
73
|
-
let result = context[variable];
|
|
74
|
-
for (const property of properties) {
|
|
75
|
-
if (typeof result !== "object" || result === null)
|
|
76
|
-
throw new Error("Property access attempt on non-object.");
|
|
77
|
-
result = (result as Record<string, unknown>)[property];
|
|
78
|
-
}
|
|
79
|
-
return result;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
export type Token =
|
|
2
|
-
| TextToken
|
|
3
|
-
| InterpolationToken
|
|
4
|
-
| OpenToken
|
|
5
|
-
| CloseToken
|
|
6
|
-
| ArgumentsToken;
|
|
7
|
-
|
|
8
|
-
type TextToken = {
|
|
9
|
-
type: "text";
|
|
10
|
-
text: string;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
type InterpolationToken = {
|
|
14
|
-
type: "interpolation";
|
|
15
|
-
value: string;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
type OpenToken = {
|
|
19
|
-
type: "open";
|
|
20
|
-
tag: string;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
type CloseToken = {
|
|
24
|
-
type: "close";
|
|
25
|
-
tag: string;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
type ArgumentsToken = {
|
|
29
|
-
type: "arguments";
|
|
30
|
-
value: string[];
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export function tokenize(input: string): Token[] {
|
|
34
|
-
const tokens: Token[] = [];
|
|
35
|
-
let textBuffer = "";
|
|
36
|
-
for (let i = 0; i < input.length; i++) {
|
|
37
|
-
const char = input[i];
|
|
38
|
-
if (char === "{") {
|
|
39
|
-
pushTextBuffer();
|
|
40
|
-
const read = readTill("}", i, input);
|
|
41
|
-
if (!read.success) throw new Error("Unable to find closing }");
|
|
42
|
-
const { value, finishingPosition } = read;
|
|
43
|
-
tokens.push({
|
|
44
|
-
type: "interpolation",
|
|
45
|
-
value,
|
|
46
|
-
});
|
|
47
|
-
i = finishingPosition;
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (char === "<") {
|
|
52
|
-
pushTextBuffer();
|
|
53
|
-
const read = readTill(">", i, input);
|
|
54
|
-
if (!read.success) throw new Error("Unable to find closing '>'");
|
|
55
|
-
const { value, finishingPosition } = read;
|
|
56
|
-
const values = value.trim().split(/\s+/);
|
|
57
|
-
const tag = values[0];
|
|
58
|
-
if (tag === undefined) throw new Error("Unable to find tag name");
|
|
59
|
-
if (tag[0] === "/") {
|
|
60
|
-
const tagName = tag.substring(1);
|
|
61
|
-
tokens.push({
|
|
62
|
-
type: "close",
|
|
63
|
-
tag: tagName,
|
|
64
|
-
});
|
|
65
|
-
i = finishingPosition;
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
const args = values.slice(1);
|
|
69
|
-
tokens.push({
|
|
70
|
-
type: "open",
|
|
71
|
-
tag,
|
|
72
|
-
});
|
|
73
|
-
if (args.length > 0) {
|
|
74
|
-
tokens.push({
|
|
75
|
-
type: "arguments",
|
|
76
|
-
value: args,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
i = finishingPosition;
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
textBuffer += char;
|
|
85
|
-
}
|
|
86
|
-
pushTextBuffer();
|
|
87
|
-
return tokens;
|
|
88
|
-
|
|
89
|
-
function pushTextBuffer() {
|
|
90
|
-
if (textBuffer.length > 0) {
|
|
91
|
-
tokens.push({
|
|
92
|
-
type: "text",
|
|
93
|
-
text: textBuffer,
|
|
94
|
-
});
|
|
95
|
-
textBuffer = "";
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function readTill(
|
|
101
|
-
charToSearchFor: string,
|
|
102
|
-
startingPosition: number,
|
|
103
|
-
text: string,
|
|
104
|
-
):
|
|
105
|
-
| {
|
|
106
|
-
success: true;
|
|
107
|
-
value: string;
|
|
108
|
-
finishingPosition: number;
|
|
109
|
-
}
|
|
110
|
-
| {
|
|
111
|
-
success: false;
|
|
112
|
-
} {
|
|
113
|
-
const finishingPosition = text.indexOf(charToSearchFor, startingPosition + 1);
|
|
114
|
-
if (finishingPosition === -1) {
|
|
115
|
-
return { success: false };
|
|
116
|
-
}
|
|
117
|
-
const substring = text.substring(startingPosition + 1, finishingPosition);
|
|
118
|
-
return {
|
|
119
|
-
success: true,
|
|
120
|
-
value: substring,
|
|
121
|
-
finishingPosition,
|
|
122
|
-
};
|
|
123
|
-
}
|
package/src/routing.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import type Elysia from "elysia";
|
|
4
|
-
import type { RouteFn } from "./types";
|
|
5
|
-
|
|
6
|
-
export async function registerRoutes(
|
|
7
|
-
app: Elysia,
|
|
8
|
-
baseDir: string,
|
|
9
|
-
prefix = "/",
|
|
10
|
-
) {
|
|
11
|
-
const entries = await fs.readdir(baseDir, { withFileTypes: true });
|
|
12
|
-
for (const entry of entries) {
|
|
13
|
-
const fullPath = path.join(baseDir, entry.name);
|
|
14
|
-
if (entry.isDirectory()) {
|
|
15
|
-
await registerRoutes(app, fullPath, path.join(prefix, entry.name));
|
|
16
|
-
continue;
|
|
17
|
-
}
|
|
18
|
-
if (entry.name !== "index.ts") continue;
|
|
19
|
-
const module = (await import(fullPath)) as Record<string, unknown>;
|
|
20
|
-
const defaultFn = module.default;
|
|
21
|
-
if (defaultFn && typeof defaultFn === "function") {
|
|
22
|
-
app.all(prefix, async ({ request, query, params }) => {
|
|
23
|
-
const result = await defaultFn({ request, query, params });
|
|
24
|
-
return result;
|
|
25
|
-
});
|
|
26
|
-
console.log(`Registered ${fullPath} on ${prefix} route with method all`);
|
|
27
|
-
}
|
|
28
|
-
for (const propName in module) {
|
|
29
|
-
const prop = module[propName];
|
|
30
|
-
if (typeof prop !== "function") continue;
|
|
31
|
-
const fn = prop as RouteFn;
|
|
32
|
-
const name = fn.name.toLowerCase();
|
|
33
|
-
if (!["get", "post", "put", "patch", "delete"].includes(name)) continue;
|
|
34
|
-
app[name as "get"](prefix, async ({ request, query, params }) => {
|
|
35
|
-
const result = await fn({ request, query, params });
|
|
36
|
-
return result;
|
|
37
|
-
});
|
|
38
|
-
console.log(
|
|
39
|
-
`Registered ${fullPath} on ${prefix} route with method ${name}`,
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export type RouteParams = {
|
|
2
|
-
query: Record<string, string>;
|
|
3
|
-
request: Request;
|
|
4
|
-
params: Record<string, string>;
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export type Paths = {
|
|
8
|
-
routes: string;
|
|
9
|
-
views: string;
|
|
10
|
-
public: string;
|
|
11
|
-
port: number;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export type RouteFn = (
|
|
15
|
-
_: RouteParams,
|
|
16
|
-
) => Promise<Response> | Response | Promise<string> | string;
|
package/src/views.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { parse } from "./next-parser/parser";
|
|
4
|
-
import { render } from "./next-parser/renderer";
|
|
5
|
-
import { tokenize } from "./next-parser/tokenizer";
|
|
6
|
-
|
|
7
|
-
let viewsPath = "";
|
|
8
|
-
|
|
9
|
-
export function setViewsPath(path: string) {
|
|
10
|
-
viewsPath = path;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export async function view(view: string, props: Record<string, unknown>) {
|
|
14
|
-
if (viewsPath === "")
|
|
15
|
-
throw new Error(
|
|
16
|
-
"Views folder path not yet configured. Use `Htmv.setup` before rendering a view.",
|
|
17
|
-
);
|
|
18
|
-
const filePath = path.join(viewsPath, `${view}.html`);
|
|
19
|
-
const code = await fs.readFile(filePath, "utf-8");
|
|
20
|
-
const tokens = tokenize(code);
|
|
21
|
-
const root = parse(tokens);
|
|
22
|
-
const rendered = render(root, props);
|
|
23
|
-
return new Response(rendered, {
|
|
24
|
-
headers: { "Content-Type": "text/html; charset=utf-8" },
|
|
25
|
-
});
|
|
26
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
// Environment setup & latest features
|
|
4
|
-
"lib": ["ESNext"],
|
|
5
|
-
"target": "ESNext",
|
|
6
|
-
"module": "Preserve",
|
|
7
|
-
"moduleDetection": "force",
|
|
8
|
-
"allowJs": true,
|
|
9
|
-
|
|
10
|
-
// Bundler mode
|
|
11
|
-
"moduleResolution": "bundler",
|
|
12
|
-
"verbatimModuleSyntax": true,
|
|
13
|
-
|
|
14
|
-
// Best practices
|
|
15
|
-
"strict": true,
|
|
16
|
-
"skipLibCheck": true,
|
|
17
|
-
"noFallthroughCasesInSwitch": true,
|
|
18
|
-
"noUncheckedIndexedAccess": true,
|
|
19
|
-
"noImplicitOverride": true,
|
|
20
|
-
|
|
21
|
-
// Some stricter flags (disabled by default)
|
|
22
|
-
"noUnusedLocals": false,
|
|
23
|
-
"noUnusedParameters": false,
|
|
24
|
-
"noPropertyAccessFromIndexSignature": false,
|
|
25
|
-
|
|
26
|
-
// Config for npm
|
|
27
|
-
"noEmit": false, // Changed to false to allow it to compile
|
|
28
|
-
"outDir": "./dist",
|
|
29
|
-
"declaration": true //generates .d.ts
|
|
30
|
-
},
|
|
31
|
-
"include": ["src"]
|
|
32
|
-
}
|