htmv 0.0.25 → 0.0.26

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.
@@ -20,5 +20,8 @@ jobs:
20
20
  - name: Install dependencies
21
21
  run: bun install
22
22
 
23
+ - name: Lint
24
+ run: npm run lint
25
+
23
26
  - name: Run TypeScript build
24
27
  run: npm run build
@@ -32,6 +32,9 @@ jobs:
32
32
  - name: Install dependencies
33
33
  run: bun install
34
34
 
35
+ - name: Lint
36
+ run: npm run lint
37
+
35
38
  - name: Build (tsc)
36
39
  run: npm run build
37
40
 
package/README.md CHANGED
@@ -77,6 +77,18 @@ Supported methods currently are:
77
77
  - DELETE
78
78
  - ALL (add `default` keyword)
79
79
 
80
+ # Renaming folders
81
+ If you wish to rename either the `views`, `routes` or `public` folders you can do so in `index.ts` as follows:
82
+ ```ts
83
+ setup({
84
+ routes: path.join(dirPath, "my_custom_routes_folder"),
85
+ views: path.join(dirPath, "stuff", "views"),
86
+ public: path.join(dirPath, "static"),
87
+ port: 3000,
88
+ });
89
+ ```
90
+ Just change the string for the new name you wish for. Note that when doing so `htmv gen` will now need `--path` flag passed to know where to find them.
91
+
80
92
  # Code generation
81
93
  Do you often forget how to write boilerplate code? Why not just let HTMV do it for you?
82
94
  As you know, HTMV comes with the CLI tool you used when creating the project. But it also has the command `htmv gen` which allows you to generate a basic template for a view or route.
package/biome.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.3.3/schema.json",
3
+ "vcs": {
4
+ "enabled": true,
5
+ "clientKind": "git",
6
+ "useIgnoreFile": true
7
+ },
8
+ "files": {
9
+ "includes": ["**", "!!**/dist"]
10
+ },
11
+ "formatter": {
12
+ "enabled": true,
13
+ "indentStyle": "tab"
14
+ },
15
+ "linter": {
16
+ "enabled": true,
17
+ "rules": {
18
+ "recommended": true
19
+ }
20
+ },
21
+ "javascript": {
22
+ "formatter": {
23
+ "quoteStyle": "double"
24
+ }
25
+ },
26
+ "assist": {
27
+ "enabled": true,
28
+ "actions": {
29
+ "source": {
30
+ "organizeImports": "on"
31
+ }
32
+ }
33
+ }
34
+ }
package/dist/app.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ import { Elysia } from "elysia";
2
+ export declare function createApp(publicPath: string): Elysia<"", {
3
+ decorator: {};
4
+ store: {};
5
+ derive: {};
6
+ resolve: {};
7
+ }, {
8
+ typebox: {};
9
+ error: {};
10
+ }, {
11
+ schema: {};
12
+ standaloneSchema: {};
13
+ macro: {};
14
+ macroFn: {};
15
+ parser: {};
16
+ response: {};
17
+ }, {}, {
18
+ derive: {};
19
+ resolve: {};
20
+ schema: {};
21
+ standaloneSchema: {};
22
+ response: {};
23
+ }, {
24
+ derive: {};
25
+ resolve: {};
26
+ schema: {};
27
+ standaloneSchema: {};
28
+ response: {};
29
+ } & {
30
+ derive: {};
31
+ resolve: {};
32
+ schema: {};
33
+ standaloneSchema: {};
34
+ response: {};
35
+ }>;
package/dist/app.js ADDED
@@ -0,0 +1,7 @@
1
+ import staticPlugin from "@elysiajs/static";
2
+ import { Elysia } from "elysia";
3
+ export function createApp(publicPath) {
4
+ return new Elysia().use(staticPlugin({
5
+ assets: publicPath,
6
+ }));
7
+ }
package/dist/index.d.ts CHANGED
@@ -1,14 +1,3 @@
1
- export declare function view(view: string, props: Record<string, unknown>): Promise<Response>;
2
- export type RouteParams = {
3
- query: Record<string, string>;
4
- request: Request;
5
- params: Record<string, string>;
6
- };
7
- type Paths = {
8
- routes: string;
9
- views: string;
10
- public: string;
11
- port: number;
12
- };
1
+ import type { Paths } from "./types";
2
+ export { view } from "./views";
13
3
  export declare function setup(paths: Paths): Promise<void>;
14
- export {};
package/dist/index.js CHANGED
@@ -1,63 +1,13 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- import staticPlugin from "@elysiajs/static";
4
- import { Elysia } from "elysia";
5
- let viewsPath = "";
6
- export async function view(view, props) {
7
- if (viewsPath === "")
8
- throw new Error("Views folder path not yet configured. Use `Htmv.setup` before rendering a view.");
9
- const filePath = path.join(viewsPath, `${view}.html`);
10
- const code = await fs.readFile(filePath, "utf-8");
11
- const replacedCode = code.replace(/{(.+)}/g, (_, propName) => {
12
- return props[propName];
13
- });
14
- return new Response(replacedCode, {
15
- headers: { "Content-Type": "text/html; charset=utf-8" },
16
- });
17
- }
1
+ import { createApp } from "./app";
2
+ import { registerRoutes } from "./routing";
3
+ import { setViewsPath } from "./views";
4
+ export { view } from "./views";
18
5
  export async function setup(paths) {
19
- viewsPath = paths.views;
20
- const app = new Elysia().use(staticPlugin({
21
- assets: paths.public,
22
- }));
6
+ setViewsPath(paths.views);
7
+ const app = createApp(paths.public);
23
8
  await registerRoutes(app, paths.routes);
24
9
  app.listen(paths.port);
25
10
  console.log("");
26
11
  console.log(`HTMV running on port ${paths.port}! 🎉`);
27
12
  console.log(`http://localhost:${paths.port}`);
28
13
  }
29
- async function registerRoutes(app, baseDir, prefix = "/") {
30
- const entries = await fs.readdir(baseDir, { withFileTypes: true });
31
- for (const entry of entries) {
32
- const fullPath = path.join(baseDir, entry.name);
33
- if (entry.isDirectory()) {
34
- await registerRoutes(app, fullPath, path.join(prefix, entry.name));
35
- continue;
36
- }
37
- if (entry.name !== "index.ts")
38
- continue;
39
- const module = (await import(fullPath));
40
- const defaultFn = module.default;
41
- if (defaultFn && typeof defaultFn === "function") {
42
- app.all(prefix, async ({ request, query, params }) => {
43
- const result = await defaultFn({ request, query, params });
44
- return result;
45
- });
46
- console.log(`Registered ${fullPath} on ${prefix} route with method all`);
47
- }
48
- for (const propName in module) {
49
- const prop = module[propName];
50
- if (typeof prop !== "function")
51
- continue;
52
- const fn = prop;
53
- const name = fn.name.toLowerCase();
54
- if (!["get", "post", "put", "patch", "delete"].includes(name))
55
- continue;
56
- app[name](prefix, async ({ request, query, params }) => {
57
- const result = await fn({ request, query, params });
58
- return result;
59
- });
60
- console.log(`Registered ${fullPath} on ${prefix} route with method ${name}`);
61
- }
62
- }
63
- }
@@ -0,0 +1,2 @@
1
+ import type Elysia from "elysia";
2
+ export declare function registerRoutes(app: Elysia, baseDir: string, prefix?: string): Promise<void>;
@@ -0,0 +1,37 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ export async function registerRoutes(app, baseDir, prefix = "/") {
4
+ const entries = await fs.readdir(baseDir, { withFileTypes: true });
5
+ for (const entry of entries) {
6
+ const fullPath = path.join(baseDir, entry.name);
7
+ if (entry.isDirectory()) {
8
+ await registerRoutes(app, fullPath, path.join(prefix, entry.name));
9
+ continue;
10
+ }
11
+ if (entry.name !== "index.ts")
12
+ continue;
13
+ const module = (await import(fullPath));
14
+ const defaultFn = module.default;
15
+ if (defaultFn && typeof defaultFn === "function") {
16
+ app.all(prefix, async ({ request, query, params }) => {
17
+ const result = await defaultFn({ request, query, params });
18
+ return result;
19
+ });
20
+ console.log(`Registered ${fullPath} on ${prefix} route with method all`);
21
+ }
22
+ for (const propName in module) {
23
+ const prop = module[propName];
24
+ if (typeof prop !== "function")
25
+ continue;
26
+ const fn = prop;
27
+ const name = fn.name.toLowerCase();
28
+ if (!["get", "post", "put", "patch", "delete"].includes(name))
29
+ continue;
30
+ app[name](prefix, async ({ request, query, params }) => {
31
+ const result = await fn({ request, query, params });
32
+ return result;
33
+ });
34
+ console.log(`Registered ${fullPath} on ${prefix} route with method ${name}`);
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,2 @@
1
+ export declare function setViewsPath(path: string): void;
2
+ export declare function view(view: string, props: Record<string, unknown>): Promise<Response>;
package/dist/views.js ADDED
@@ -0,0 +1,24 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ let viewsPath = "";
4
+ export function setViewsPath(path) {
5
+ viewsPath = path;
6
+ }
7
+ export async function view(view, props) {
8
+ if (viewsPath === "")
9
+ throw new Error("Views folder path not yet configured. Use `Htmv.setup` before rendering a view.");
10
+ const filePath = path.join(viewsPath, `${view}.html`);
11
+ const code = await fs.readFile(filePath, "utf-8");
12
+ const replacedCode = code
13
+ .replace(/{(.+)}/g, (_, propName) => {
14
+ return props[propName];
15
+ })
16
+ .replace(/<Isset\s+(\w+)>([\s\S]*?)<\/Isset>/g, (_, propName, innerContent) => {
17
+ if (props[propName] !== undefined && props[propName] !== null)
18
+ return innerContent;
19
+ return "";
20
+ });
21
+ return new Response(replacedCode, {
22
+ headers: { "Content-Type": "text/html; charset=utf-8" },
23
+ });
24
+ }
package/package.json CHANGED
@@ -1,29 +1,30 @@
1
1
  {
2
- "name": "htmv",
3
- "main": "dist/index.js",
4
- "type": "module",
5
- "version": "0.0.25",
6
- "devDependencies": {
7
- "@biomejs/biome": "2.3.3",
8
- "@types/bun": "latest"
9
- },
10
- "peerDependencies": {
11
- "typescript": "^5"
12
- },
13
- "dependencies": {
14
- "@elysiajs/node": "^1.4.2",
15
- "@elysiajs/static": "^1.4.6",
16
- "elysia": "^1.4.18"
17
- },
18
- "bin": {
19
- "htmv": "dist/cli/cli.js"
20
- },
21
- "scripts": {
22
- "build": "tsc",
23
- "prepublishOnly": "npm run build"
24
- },
25
- "repository": {
26
- "type": "git",
27
- "url": "https://github.com/Fabrisdev/htmv"
28
- }
2
+ "name": "htmv",
3
+ "main": "dist/index.js",
4
+ "type": "module",
5
+ "version": "0.0.26",
6
+ "devDependencies": {
7
+ "@biomejs/biome": "2.3.3",
8
+ "@types/bun": "latest"
9
+ },
10
+ "peerDependencies": {
11
+ "typescript": "^5"
12
+ },
13
+ "dependencies": {
14
+ "@elysiajs/node": "^1.4.2",
15
+ "@elysiajs/static": "^1.4.6",
16
+ "elysia": "^1.4.18"
17
+ },
18
+ "bin": {
19
+ "htmv": "dist/cli/cli.js"
20
+ },
21
+ "scripts": {
22
+ "build": "tsc",
23
+ "lint": "biome check",
24
+ "prepublishOnly": "npm run build"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/Fabrisdev/htmv"
29
+ }
29
30
  }
package/src/app.ts ADDED
@@ -0,0 +1,10 @@
1
+ import staticPlugin from "@elysiajs/static";
2
+ import { Elysia } from "elysia";
3
+
4
+ export function createApp(publicPath: string) {
5
+ return new Elysia().use(
6
+ staticPlugin({
7
+ assets: publicPath,
8
+ }),
9
+ );
10
+ }
package/src/index.ts CHANGED
@@ -1,87 +1,16 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- import staticPlugin from "@elysiajs/static";
4
- import { Elysia } from "elysia";
1
+ import { createApp } from "./app";
2
+ import { registerRoutes } from "./routing";
3
+ import type { Paths } from "./types";
4
+ import { setViewsPath } from "./views";
5
5
 
6
- let viewsPath = "";
6
+ export { view } from "./views";
7
7
 
8
- export async function view(view: string, props: Record<string, unknown>) {
9
- if (viewsPath === "")
10
- throw new Error(
11
- "Views folder path not yet configured. Use `Htmv.setup` before rendering a view.",
12
- );
13
- const filePath = path.join(viewsPath, `${view}.html`);
14
- const code = await fs.readFile(filePath, "utf-8");
15
- const replacedCode = code.replace(/{(.+)}/g, (_, propName) => {
16
- return props[propName] as string;
17
- });
18
- return new Response(replacedCode, {
19
- headers: { "Content-Type": "text/html; charset=utf-8" },
20
- });
21
- }
22
-
23
- export type RouteParams = {
24
- query: Record<string, string>;
25
- request: Request;
26
- params: Record<string, string>;
27
- };
28
-
29
- type Paths = {
30
- routes: string;
31
- views: string;
32
- public: string;
33
- port: number;
34
- };
35
8
  export async function setup(paths: Paths) {
36
- viewsPath = paths.views;
37
- const app = new Elysia().use(
38
- staticPlugin({
39
- assets: paths.public,
40
- }),
41
- );
42
-
9
+ setViewsPath(paths.views);
10
+ const app = createApp(paths.public);
43
11
  await registerRoutes(app, paths.routes);
44
12
  app.listen(paths.port);
45
13
  console.log("");
46
14
  console.log(`HTMV running on port ${paths.port}! 🎉`);
47
15
  console.log(`http://localhost:${paths.port}`);
48
16
  }
49
-
50
- async function registerRoutes(app: Elysia, baseDir: string, prefix = "/") {
51
- const entries = await fs.readdir(baseDir, { withFileTypes: true });
52
- for (const entry of entries) {
53
- const fullPath = path.join(baseDir, entry.name);
54
- if (entry.isDirectory()) {
55
- await registerRoutes(app, fullPath, path.join(prefix, entry.name));
56
- continue;
57
- }
58
- if (entry.name !== "index.ts") continue;
59
- const module = (await import(fullPath)) as Record<string, unknown>;
60
- const defaultFn = module.default;
61
- if (defaultFn && typeof defaultFn === "function") {
62
- app.all(prefix, async ({ request, query, params }) => {
63
- const result = await defaultFn({ request, query, params });
64
- return result;
65
- });
66
- console.log(`Registered ${fullPath} on ${prefix} route with method all`);
67
- }
68
- for (const propName in module) {
69
- const prop = module[propName];
70
- if (typeof prop !== "function") continue;
71
- const fn = prop as RouteFn;
72
- const name = fn.name.toLowerCase();
73
- if (!["get", "post", "put", "patch", "delete"].includes(name)) continue;
74
- app[name as "get"](prefix, async ({ request, query, params }) => {
75
- const result = await fn({ request, query, params });
76
- return result;
77
- });
78
- console.log(
79
- `Registered ${fullPath} on ${prefix} route with method ${name}`,
80
- );
81
- }
82
- }
83
- }
84
-
85
- type RouteFn = (
86
- _: RouteParams,
87
- ) => Promise<Response> | Response | Promise<string> | string;
package/src/routing.ts ADDED
@@ -0,0 +1,43 @@
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.d.ts ADDED
@@ -0,0 +1,16 @@
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 ADDED
@@ -0,0 +1,32 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ let viewsPath = "";
5
+
6
+ export function setViewsPath(path: string) {
7
+ viewsPath = path;
8
+ }
9
+
10
+ export async function view(view: string, props: Record<string, unknown>) {
11
+ if (viewsPath === "")
12
+ throw new Error(
13
+ "Views folder path not yet configured. Use `Htmv.setup` before rendering a view.",
14
+ );
15
+ const filePath = path.join(viewsPath, `${view}.html`);
16
+ const code = await fs.readFile(filePath, "utf-8");
17
+ const replacedCode = code
18
+ .replace(/{(.+)}/g, (_, propName) => {
19
+ return props[propName] as string;
20
+ })
21
+ .replace(
22
+ /<Isset\s+(\w+)>([\s\S]*?)<\/Isset>/g,
23
+ (_, propName, innerContent) => {
24
+ if (props[propName] !== undefined && props[propName] !== null)
25
+ return innerContent;
26
+ return "";
27
+ },
28
+ );
29
+ return new Response(replacedCode, {
30
+ headers: { "Content-Type": "text/html; charset=utf-8" },
31
+ });
32
+ }
package/tsconfig.json CHANGED
@@ -1,33 +1,32 @@
1
1
  {
2
- "compilerOptions": {
3
- // Environment setup & latest features
4
- "lib": ["ESNext"],
5
- "target": "ESNext",
6
- "module": "Preserve",
7
- "moduleDetection": "force",
8
- "allowJs": true,
2
+ "compilerOptions": {
3
+ // Environment setup & latest features
4
+ "lib": ["ESNext"],
5
+ "target": "ESNext",
6
+ "module": "Preserve",
7
+ "moduleDetection": "force",
8
+ "allowJs": true,
9
9
 
10
- // Bundler mode
11
- "moduleResolution": "bundler",
12
- "verbatimModuleSyntax": true,
10
+ // Bundler mode
11
+ "moduleResolution": "bundler",
12
+ "verbatimModuleSyntax": true,
13
13
 
14
- // Best practices
15
- "strict": true,
16
- "skipLibCheck": true,
17
- "noFallthroughCasesInSwitch": true,
18
- "noUncheckedIndexedAccess": true,
19
- "noImplicitOverride": true,
14
+ // Best practices
15
+ "strict": true,
16
+ "skipLibCheck": true,
17
+ "noFallthroughCasesInSwitch": true,
18
+ "noUncheckedIndexedAccess": true,
19
+ "noImplicitOverride": true,
20
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
- },
32
- "include": ["src"]
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"]
33
32
  }