elysia-autoload 1.5.2 → 1.7.0

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 CHANGED
@@ -41,6 +41,26 @@ const app = new Elysia().use(await autoload()).listen(3000);
41
41
  export type ElysiaApp = typeof app;
42
42
  ```
43
43
 
44
+ ### With custom options
45
+
46
+ ```ts
47
+ import { Elysia } from "elysia";
48
+ import { autoload } from "elysia-autoload";
49
+
50
+ const app = new Elysia()
51
+ .use(
52
+ await autoload({
53
+ dir: "./routes",
54
+ prefix: "/api",
55
+ // Ignore test files and spec files
56
+ ignore: ["**/*.test.ts", "**/*.spec.ts"]
57
+ })
58
+ )
59
+ .listen(3000);
60
+
61
+ export type ElysiaApp = typeof app;
62
+ ```
63
+
44
64
  > [!IMPORTANT]
45
65
  > We strictly recommend use `await` when registering plugin
46
66
  >
@@ -99,6 +119,7 @@ Guide how `elysia-autoload` match routes
99
119
  | prefix? | string | | Prefix for routes |
100
120
  | types? | boolean \| [Types Options](#types-options) | false | Options to configure type code-generation. if boolean - enables/disables generation |
101
121
  | schema? | Function | | Handler for providing routes guard schema |
122
+ | ignore? | string \| string[] | | Glob pattern(s) to ignore when discovering files |
102
123
 
103
124
  ### Types Options
104
125
 
package/dist/index.d.ts CHANGED
@@ -53,6 +53,15 @@ interface AutoloadOptions {
53
53
  * @default false
54
54
  */
55
55
  skipImportErrors?: boolean;
56
+ /**
57
+ * Glob pattern(s) to ignore when discovering files
58
+ */
59
+ ignore?: string | string[];
60
+ /**
61
+ * Path to tsconfig.json file for module resolution detection
62
+ * @default "tsconfig.json"
63
+ */
64
+ tsconfigPath?: string;
56
65
  }
57
66
  declare function autoload(options?: AutoloadOptions): Promise<Elysia$1<string, {
58
67
  decorator: {};
package/dist/index.js CHANGED
@@ -30,7 +30,37 @@ const IS_BUN = typeof Bun !== "undefined";
30
30
  function globSync(globPattern, globOptions) {
31
31
  return IS_BUN ? Array.from(new Bun.Glob(globPattern).scanSync(globOptions)) : fs.globSync(globPattern, globOptions);
32
32
  }
33
+ function matchesPattern(filePath, pattern) {
34
+ if (IS_BUN) {
35
+ const glob = new Bun.Glob(pattern);
36
+ return glob.match(filePath);
37
+ }
38
+ let regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\\\*/g, "*").replace(/\\\?/g, "?");
39
+ regexPattern = regexPattern.replace(/\*\*/g, "\xA7\xA7\xA7").replace(/\*/g, "[^/]*").replace(/§§§/g, ".*").replace(/\?/g, ".").replace(/\{([^}]+)\}/g, (_, group) => {
40
+ const options = group.split(",").map((s) => s.trim());
41
+ return `(${options.join("|")})`;
42
+ });
43
+ const regex = new RegExp(`^${regexPattern}$`);
44
+ return regex.test(filePath);
45
+ }
33
46
 
47
+ async function shouldKeepTsExtension(tsconfigPath) {
48
+ try {
49
+ const configPath = tsconfigPath ? path.resolve(tsconfigPath) : path.join(process.cwd(), "tsconfig.json");
50
+ let fileContent;
51
+ if (typeof Bun === "undefined") {
52
+ fileContent = fs.readFileSync(configPath, "utf-8");
53
+ } else {
54
+ fileContent = await Bun.file(configPath).text();
55
+ }
56
+ const tsConfig = JSON.parse(fileContent);
57
+ const moduleOption = (tsConfig.compilerOptions?.module || "").toLowerCase();
58
+ const moduleResolutionOption = (tsConfig.compilerOptions?.moduleResolution || "").toLowerCase();
59
+ return moduleOption === "nodenext" || moduleOption === "node16" || moduleResolutionOption === "nodenext" || moduleResolutionOption === "node16";
60
+ } catch (error) {
61
+ return false;
62
+ }
63
+ }
34
64
  const DIR_ROUTES_DEFAULT = "./routes";
35
65
  const TYPES_OUTPUT_DEFAULT = "./routes-types.ts";
36
66
  const TYPES_TYPENAME_DEFAULT = "Routes";
@@ -39,7 +69,7 @@ const TYPES_OBJECT_DEFAULT = {
39
69
  typeName: TYPES_TYPENAME_DEFAULT
40
70
  };
41
71
  async function autoload(options = {}) {
42
- const { pattern, prefix, schema } = options;
72
+ const { pattern, prefix, schema, ignore, tsconfigPath } = options;
43
73
  const failGlob = options.failGlob ?? true;
44
74
  const getImportName = options?.import ?? "default";
45
75
  const dir = options.dir ?? DIR_ROUTES_DEFAULT;
@@ -61,12 +91,21 @@ async function autoload(options = {}) {
61
91
  pattern,
62
92
  dir,
63
93
  prefix,
64
- types
94
+ types,
95
+ ignore
65
96
  }
66
97
  });
67
98
  const globPattern = pattern || "**/*.{ts,tsx,js,jsx,mjs,cjs}";
68
99
  const globOptions = { cwd: directoryPath };
69
- const files = globSync(globPattern, globOptions);
100
+ let files = globSync(globPattern, globOptions);
101
+ if (ignore) {
102
+ const ignorePatterns = Array.isArray(ignore) ? ignore : [ignore];
103
+ files = files.filter((filePath) => {
104
+ return !ignorePatterns.some(
105
+ (pattern2) => matchesPattern(filePath, pattern2)
106
+ );
107
+ });
108
+ }
70
109
  if (failGlob && files.length === 0)
71
110
  throw new Error(
72
111
  `No matches found in ${directoryPath}. You can disable this error by setting the failGlob parameter to false in the options of autoload plugin`
@@ -92,16 +131,18 @@ async function autoload(options = {}) {
92
131
  if (types) paths.push([fullPath.replace(directoryPath, ""), importName]);
93
132
  }
94
133
  if (types) {
134
+ const needsExtension = await shouldKeepTsExtension(tsconfigPath);
95
135
  for await (const outputPath of types.output) {
96
136
  const outputAbsolutePath = getPath(outputPath);
97
- const imports = paths.map(
98
- ([x, exportName], index) => `import type ${exportName === "default" ? `Route${index}` : `{ ${exportName} as Route${index} }`} from "${addRelativeIfNotDot(
137
+ const imports = paths.map(([filePath, exportName], index) => {
138
+ const importPath = needsExtension ? filePath : filePath.replace(/\.(ts|tsx)$/, "");
139
+ return `import type ${exportName === "default" ? `Route${index}` : `{ ${exportName} as Route${index} }`} from "${addRelativeIfNotDot(
99
140
  path.relative(
100
141
  path.dirname(outputAbsolutePath),
101
- directoryPath + x.replace(/\.(ts|tsx)$/, "")
142
+ path.join(directoryPath, importPath)
102
143
  ).replaceAll("\\", "/")
103
- )}";`
104
- );
144
+ )}";`;
145
+ });
105
146
  const input = [
106
147
  `import type { ElysiaWithBaseUrl } from "elysia-autoload";`,
107
148
  imports.join("\n"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "elysia-autoload",
3
- "version": "1.5.2",
3
+ "version": "1.7.0",
4
4
  "author": "kravetsone",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",