@asterflow/fs 1.0.1

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/README.md ADDED
@@ -0,0 +1,121 @@
1
+ <div align="center">
2
+
3
+ # @asterflow/fs
4
+
5
+ ![license-info](https://img.shields.io/github/license/AsterFlow/plugins?style=for-the-badge&colorA=302D41&colorB=f9e2af&logoColor=f9e2af)
6
+ ![stars-info](https://img.shields.io/github/stars/AsterFlow/plugins?colorA=302D41&colorB=f9e2af&style=for-the-badge)
7
+ ![bundle-size](https://img.shields.io/bundlejs/size/@asterflow/fs?style=for-the-badge&colorA=302D41&colorB=3ac97b)
8
+
9
+ </div>
10
+
11
+ > Roteamento baseado em convenΓ§Γ΅es de sistema de arquivos para o AsterFlow.
12
+
13
+ ## πŸ“¦ Installation
14
+
15
+ ```bash
16
+ # You can use any package manager
17
+ npm install @asterflow/fs
18
+ ```
19
+
20
+ ## πŸ’‘ About
21
+
22
+ `@asterflow/fs` brings the convenience of file system-based routing to your AsterFlow projects. Inspired by modern web frameworks, this plugin automatically discovers and registers your routes based on the file and directory structure, allowing you to focus on writing your API logic instead of manual route configuration.
23
+
24
+ ## ✨ Features
25
+
26
+ - **Convention over Configuration:** Automatically generates API routes from your file structure.
27
+ - **Dynamic Parameters:** Support for dynamic segments in filenames (e.g., `$id.ts`).
28
+ - **Index Routes:** `index.ts` files are treated as the base route of a directory.
29
+ - **Type-Safe:** Fully integrated with AsterFlow's type system.
30
+ - **Seamless Integration:** Automatically registers all discovered routes before the server starts.
31
+
32
+ ## πŸš€ Usage
33
+
34
+ ### 1\. Project Structure
35
+
36
+ Create a directory to store your route files. By convention, this directory is usually `routes/` or `src/routes/`.
37
+
38
+ ```
39
+ .
40
+ β”œβ”€β”€ routes/
41
+ β”‚ β”œβ”€β”€ index.ts # Handles GET /
42
+ β”‚ β”œβ”€β”€ users/
43
+ β”‚ β”‚ β”œβ”€β”€ index.ts # Handles GET /users
44
+ β”‚ β”‚ └── $id.ts # Handles GET /users/:id
45
+ β”œβ”€β”€ src
46
+ β”‚ └── index.ts # Your main application file
47
+ └── package.json
48
+ ```
49
+
50
+ ### 2\. Define Your Routes
51
+
52
+ Each route file must have a `default export` of an AsterFlow `Method` or `Router`.
53
+
54
+ **`src/routes/users/$id.ts`**
55
+
56
+ ```typescript
57
+ import { Method } from '@asterflow/router';
58
+
59
+ export default new Method({
60
+ // The 'path' property will be overwritten by the plugin,
61
+ // but can be useful for isolated testing.
62
+ path: '/',
63
+ method: 'get',
64
+ handler({ response, url }) {
65
+ // 'id' will be available at runtime
66
+ const params = url.getParams();
67
+ return response.success({ user: { id: params.id } });
68
+ }
69
+ });
70
+ ```
71
+
72
+ ### 3\. Register the Plugin
73
+
74
+ In your main application file, import and register the `fsRouting` plugin.
75
+
76
+ **`src/index.ts`**
77
+
78
+ ```typescript
79
+ import { AsterFlow } from '@asterflow/core';
80
+ import { fsRouting } from '@asterflow/fs';
81
+ import { join } from 'path';
82
+
83
+ // Register the plugin and point it to your routes directory
84
+ export const app = new AsterFlow();
85
+ .use(fsRouting, {
86
+ path: join(process.cwd(), 'src', 'routes')
87
+ });
88
+
89
+ // Start the server
90
+ app.listen({ port: 3333 }, () => {
91
+ console.log('Server running with file system routing!');
92
+ });
93
+ ```
94
+
95
+ That's it\! The plugin will scan the `src/routes` directory and register all valid route files when the application starts.
96
+
97
+ ## πŸ—ΊοΈ Routing Conventions
98
+
99
+ The plugin transforms file paths into URL routes based on the following rules:
100
+
101
+ | File Path | Generated Route |
102
+ | ----------------- | ------------------ |
103
+ | `index.ts` | `/` |
104
+ | `users.ts` | `/users` |
105
+ | `users/index.ts` | `/users` |
106
+ | `$id.ts` | `/:id` |
107
+ | `products/$id.ts` | `/products/:id` |
108
+ | `categories/$categoryId/products/$productId.ts` | `/categories/:categoryId/products/:productId` |
109
+
110
+ - Files named `index` become the root of their directory.
111
+ - Filenames prefixed with `$` (e.g., `$id.ts`) are converted to dynamic URL parameters (e.g., `/:id`).
112
+
113
+ ## πŸ”— Related Packages
114
+
115
+ - [@asterflow/core](https://www.npmjs.com/package/@asterflow/core) - The core of the AsterFlow framework.
116
+ - [@asterflow/plugin](https://www.npmjs.com/package/@asterflow/plugin) - The main plugin system.
117
+ - [@asterflow/router](https://www.npmjs.com/package/@asterflow/router) - The type-safe routing system used by this plugin.
118
+
119
+ ## πŸ“„ License
120
+
121
+ MIT - See the main project [LICENSE](https://github.com/AsterFlow/AsterFlow/blob/main/LICENSE) for more details.
package/cjs/index.cjs ADDED
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ var a = Object.defineProperty;
3
+ var h = Object.getOwnPropertyDescriptor;
4
+ var x = Object.getOwnPropertyNames;
5
+ var w = Object.prototype.hasOwnProperty;
6
+ var A = (t, e) => {
7
+ for (var i in e)
8
+ a(t, i, { get: e[i], enumerable: !0 });
9
+ }, v = (t, e, i, r) => {
10
+ if (e && typeof e == "object" || typeof e == "function")
11
+ for (let s of x(e))
12
+ !w.call(t, s) && s !== i && a(t, s, { get: () => e[s], enumerable: !(r = h(e, s)) || r.enumerable });
13
+ return t;
14
+ };
15
+ var j = (t) => v(a({}, "__esModule", { value: !0 }), t);
16
+
17
+ // plugins/fs/src/index.ts
18
+ var b = {};
19
+ A(b, {
20
+ default: () => P,
21
+ fsRoutingPlugin: () => y,
22
+ getFilesRecursively: () => o,
23
+ transformPathToUrl: () => p
24
+ });
25
+ module.exports = j(b);
26
+ var d = require("@asterflow/plugin"), n = require("@asterflow/router"), g = require("@asterflow/url-parser");
27
+
28
+ // plugins/fs/package.json
29
+ var u = "1.0.1";
30
+
31
+ // plugins/fs/src/utils/format.ts
32
+ var c = require("path");
33
+ function p(t, e) {
34
+ let r = (0, c.relative)(e, t).replace(/\.(ts|js)$/, "");
35
+ return r.endsWith("/index") ? r = r.slice(0, -6) : r === "index" && (r = ""), r = r.replace(/\$/g, ":"), `/${r}`;
36
+ }
37
+
38
+ // plugins/fs/src/utils/glob.ts
39
+ var f = require("fs/promises"), m = require("path");
40
+ async function o(t) {
41
+ let e = await (0, f.readdir)(t, { withFileTypes: !0 });
42
+ return (await Promise.all(
43
+ e.map(async (r) => {
44
+ let s = (0, m.join)(t, r.name);
45
+ return r.isDirectory() ? o(s) : s;
46
+ })
47
+ )).flat();
48
+ }
49
+
50
+ // plugins/fs/src/index.ts
51
+ var y = d.Plugin.instance().create({ name: "fs-routing" }).decorate("creator", "Ashu11-A").decorate("version", u).config({ path: "" }).derive("files", async (t) => await o(t.path)).extends((t) => ({
52
+ async registerRoutes(e) {
53
+ if (e.files.length !== 0)
54
+ for (let i of e.files) {
55
+ let s = (await import(i)).default;
56
+ if (!s || !(s instanceof n.Method || s instanceof n.Router)) continue;
57
+ let l = p(i, e.path);
58
+ s.path = l, s.url = new g.Analyze(l), t.controller(s);
59
+ }
60
+ }
61
+ })).on("beforeInitialize", async (t, e) => await t.registerRoutes(e)), P = y;
62
+ // Annotate the CommonJS export names for ESM import in node:
63
+ 0 && (module.exports = {
64
+ fsRoutingPlugin,
65
+ getFilesRecursively,
66
+ transformPathToUrl
67
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
package/mjs/index.js ADDED
@@ -0,0 +1,46 @@
1
+ // plugins/fs/src/index.ts
2
+ import { Plugin as d } from "@asterflow/plugin";
3
+ import { Method as g, Router as y } from "@asterflow/router";
4
+ import { Analyze as h } from "@asterflow/url-parser";
5
+
6
+ // plugins/fs/package.json
7
+ var a = "1.0.1";
8
+
9
+ // plugins/fs/src/utils/format.ts
10
+ import { relative as c } from "path";
11
+ function p(t, r) {
12
+ let e = c(r, t).replace(/\.(ts|js)$/, "");
13
+ return e.endsWith("/index") ? e = e.slice(0, -6) : e === "index" && (e = ""), e = e.replace(/\$/g, ":"), `/${e}`;
14
+ }
15
+
16
+ // plugins/fs/src/utils/glob.ts
17
+ import { readdir as f } from "fs/promises";
18
+ import { join as m } from "path";
19
+ async function o(t) {
20
+ let r = await f(t, { withFileTypes: !0 });
21
+ return (await Promise.all(
22
+ r.map(async (e) => {
23
+ let s = m(t, e.name);
24
+ return e.isDirectory() ? o(s) : s;
25
+ })
26
+ )).flat();
27
+ }
28
+
29
+ // plugins/fs/src/index.ts
30
+ var x = d.instance().create({ name: "fs-routing" }).decorate("creator", "Ashu11-A").decorate("version", a).config({ path: "" }).derive("files", async (t) => await o(t.path)).extends((t) => ({
31
+ async registerRoutes(r) {
32
+ if (r.files.length !== 0)
33
+ for (let i of r.files) {
34
+ let s = (await import(i)).default;
35
+ if (!s || !(s instanceof g || s instanceof y)) continue;
36
+ let n = p(i, r.path);
37
+ s.path = n, s.url = new h(n), t.controller(s);
38
+ }
39
+ }
40
+ })).on("beforeInitialize", async (t, r) => await t.registerRoutes(r)), D = x;
41
+ export {
42
+ D as default,
43
+ x as fsRoutingPlugin,
44
+ o as getFilesRecursively,
45
+ p as transformPathToUrl
46
+ };
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@asterflow/fs",
3
+ "version": "1.0.1",
4
+ "main": "dist/cjs/index.cjs",
5
+ "module": "dist/mjs/index.js",
6
+ "types": "dist/types/index.d.ts",
7
+ "typings": "dist/types/index.d.ts",
8
+ "type": "module",
9
+ "license": "MIT",
10
+ "author": "Ashu11-A",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/AsterFlow/plugins.git"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/AsterFlow/plugins/issues"
17
+ },
18
+ "homepage": "https://github.com/AsterFlow/plugins",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/types/index.d.ts",
22
+ "import": "./dist/mjs/index.js",
23
+ "require": "./dist/cjs/index.cjs"
24
+ }
25
+ },
26
+ "engines": {
27
+ "node": ">=20"
28
+ },
29
+ "devDependencies": {
30
+ "@asterflow/core": "^1.0.7",
31
+ "@types/bun": "latest"
32
+ },
33
+ "peerDependencies": {
34
+ "typescript": "^5.8.3"
35
+ },
36
+ "dependencies": {
37
+ "@asterflow/router": "^1.0.7",
38
+ "@asterflow/url-parser": "^2.0.1"
39
+ }
40
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "compilerOptions": {
3
+ "lib": [
4
+ "ESNext"
5
+ ],
6
+ "target": "ESNext",
7
+ "module": "ESNext",
8
+ "moduleDetection": "force",
9
+ "jsx": "react-jsx",
10
+ "allowJs": true,
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "noEmit": true,
15
+ "strict": true,
16
+ "skipLibCheck": true,
17
+ "noFallthroughCasesInSwitch": true,
18
+ "noUncheckedIndexedAccess": true,
19
+ "noUnusedLocals": false,
20
+ "noUnusedParameters": false,
21
+ "noPropertyAccessFromIndexSignature": false,
22
+ "paths": {
23
+ "@asterflow/fs": [
24
+ "./types"
25
+ ],
26
+ "@asterflow/fs/*": [
27
+ "./types/*"
28
+ ]
29
+ },
30
+ "declaration": true,
31
+ "declarationMap": true
32
+ },
33
+ "include": [
34
+ "types"
35
+ ],
36
+ "exclude": [
37
+ "node_modules",
38
+ "**/*.spec.ts"
39
+ ]
40
+ }
@@ -0,0 +1,53 @@
1
+ // Generated by dts-bundle-generator v9.5.1
2
+
3
+ import { Plugin } from '@asterflow/plugin';
4
+
5
+ export declare const fsRoutingPlugin: Plugin<"fs-routing", import("@asterflow/core").IAsterflow<import("@asterflow/core").AnyReminist, {}, [
6
+ ], import("@asterflow/adapter").Adapter<import("@asterflow/adapter").Runtime.Node>, {}>, {
7
+ path: string;
8
+ }, {
9
+ creator: string;
10
+ } & {
11
+ version: string;
12
+ } & {
13
+ files: string[];
14
+ }, Omit<{}, Event> & {
15
+ beforeInitialize: [
16
+ (instance: import("@asterflow/core").IAsterflow<import("@asterflow/core").AnyReminist, {}, [
17
+ ], import("@asterflow/adapter").Adapter<import("@asterflow/adapter").Runtime.Node>, {}> & {
18
+ registerRoutes(context: FSRoutingContext): Promise<void>;
19
+ }, context: {
20
+ creator: string;
21
+ } & {
22
+ version: string;
23
+ } & {
24
+ files: string[];
25
+ } & {
26
+ path: string;
27
+ }) => Promise<void>
28
+ ];
29
+ }, {
30
+ registerRoutes(context: FSRoutingContext): Promise<void>;
31
+ }>;
32
+ /**
33
+ * Recursively lists files from a starting directory.
34
+ * @param dirPath The path to the starting directory.
35
+ * @returns A promise that resolves to an array of file paths.
36
+ */
37
+ export declare function getFilesRecursively(dirPath: string): Promise<string[]>;
38
+ /**
39
+ * Transforms a file path into a robustly formatted URL route.
40
+ */
41
+ export declare function transformPathToUrl(filePath: string, rootDir: string): string;
42
+ export type FSRoutingContext = {
43
+ path: string;
44
+ files: string[];
45
+ creator: string;
46
+ version: string;
47
+ };
48
+
49
+ export {
50
+ fsRoutingPlugin as default,
51
+ };
52
+
53
+ export {};