fragment-ts 1.0.17 → 1.0.18

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 (33) hide show
  1. package/SETUP.md +570 -0
  2. package/changes/1.md +420 -0
  3. package/dist/cli/commands/init.command.js +4 -4
  4. package/dist/cli/commands/init.command.js.map +1 -1
  5. package/dist/cli/commands/test.command.d.ts +6 -0
  6. package/dist/cli/commands/test.command.d.ts.map +1 -0
  7. package/dist/cli/commands/test.command.js +311 -0
  8. package/dist/cli/commands/test.command.js.map +1 -0
  9. package/dist/cli/index.js +6 -3
  10. package/dist/cli/index.js.map +1 -1
  11. package/dist/core/container/di-container.d.ts +5 -0
  12. package/dist/core/container/di-container.d.ts.map +1 -1
  13. package/dist/core/container/di-container.js +121 -21
  14. package/dist/core/container/di-container.js.map +1 -1
  15. package/dist/core/decorators/controller.decorator.js +5 -5
  16. package/dist/core/decorators/injection.decorators.d.ts +44 -1
  17. package/dist/core/decorators/injection.decorators.d.ts.map +1 -1
  18. package/dist/core/decorators/injection.decorators.js +92 -1
  19. package/dist/core/decorators/injection.decorators.js.map +1 -1
  20. package/dist/core/metadata/metadata-keys.d.ts +29 -17
  21. package/dist/core/metadata/metadata-keys.d.ts.map +1 -1
  22. package/dist/core/metadata/metadata-keys.js +35 -17
  23. package/dist/core/metadata/metadata-keys.js.map +1 -1
  24. package/package.json +1 -1
  25. package/src/cli/commands/init.command.ts +4 -4
  26. package/src/cli/commands/test.command.ts +289 -0
  27. package/src/cli/index.ts +16 -11
  28. package/src/core/container/di-container.ts +166 -31
  29. package/src/core/decorators/DECORATOR_USAGE.md +326 -0
  30. package/src/core/decorators/controller.decorator.ts +9 -9
  31. package/src/core/decorators/injection.decorators.ts +129 -5
  32. package/src/core/metadata/metadata-keys.ts +44 -18
  33. package/src/testing/TEST.md +321 -0
@@ -1 +1 @@
1
- {"version":3,"file":"injection.decorators.d.ts","sourceRoot":"","sources":["../../../src/core/decorators/injection.decorators.ts"],"names":[],"mappings":"AAEA,wBAAgB,SAAS,IAAI,iBAAiB,CAK7C;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAIvD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAIzD;AAED,wBAAgB,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,CAI3D"}
1
+ {"version":3,"file":"injection.decorators.d.ts","sourceRoot":"","sources":["../../../src/core/decorators/injection.decorators.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,SAAS,IAAI,iBAAiB,CAe7C;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,iBAAiB,CAIlE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,iBAAiB,CASpE;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAIzD;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,CAS3D;AAED;;;GAGG;AACH,wBAAgB,QAAQ,IAAI,iBAAiB,CAI5C;AAED;;;GAGG;AACH,wBAAgB,IAAI,IAAI,iBAAiB,CAwBxC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,eAAe,CAY/C;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,eAAe,CAY5C"}
@@ -2,28 +2,119 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Autowired = Autowired;
4
4
  exports.Inject = Inject;
5
+ exports.InjectRepository = InjectRepository;
5
6
  exports.Qualifier = Qualifier;
6
7
  exports.Value = Value;
8
+ exports.Optional = Optional;
9
+ exports.Lazy = Lazy;
10
+ exports.PostConstruct = PostConstruct;
11
+ exports.PreDestroy = PreDestroy;
7
12
  const metadata_keys_1 = require("../metadata/metadata-keys");
13
+ /**
14
+ * @Autowired - Automatically inject dependencies by type
15
+ * Usage: @Autowired() private myService: MyService;
16
+ */
8
17
  function Autowired() {
9
18
  return (target, propertyKey) => {
10
- const type = Reflect.getMetadata('design:type', target, propertyKey);
19
+ // Get the design type from TypeScript metadata
20
+ const type = Reflect.getMetadata("design:type", target, propertyKey);
21
+ if (!type || type === Object) {
22
+ throw new Error(`Cannot use @Autowired on property "${String(propertyKey)}" in ${target.constructor.name}. ` +
23
+ `Make sure TypeScript emitDecoratorMetadata is enabled and the type is explicitly declared.`);
24
+ }
25
+ // Store the type in metadata so DI container can resolve it
11
26
  Reflect.defineMetadata(metadata_keys_1.METADATA_KEYS.AUTOWIRED, type, target, propertyKey);
12
27
  };
13
28
  }
29
+ /**
30
+ * @Inject - Inject dependency by token (string or class)
31
+ * Usage: @Inject('MyService') private service: MyService;
32
+ * or: @Inject(MyService) private service: MyService;
33
+ */
14
34
  function Inject(token) {
15
35
  return (target, propertyKey) => {
16
36
  Reflect.defineMetadata(metadata_keys_1.METADATA_KEYS.INJECT, token, target, propertyKey);
17
37
  };
18
38
  }
39
+ /**
40
+ * @InjectRepository - Inject TypeORM repository for an entity
41
+ * Usage: @InjectRepository(User) private userRepo: Repository<User>;
42
+ */
43
+ function InjectRepository(entity) {
44
+ return (target, propertyKey) => {
45
+ Reflect.defineMetadata(metadata_keys_1.METADATA_KEYS.INJECT_REPOSITORY, entity, target, propertyKey);
46
+ };
47
+ }
48
+ /**
49
+ * @Qualifier - Specify which bean to inject when multiple exist
50
+ * Usage: @Qualifier('primary') @Autowired() private service: MyService;
51
+ */
19
52
  function Qualifier(name) {
20
53
  return (target, propertyKey) => {
21
54
  Reflect.defineMetadata(metadata_keys_1.METADATA_KEYS.QUALIFIER, name, target, propertyKey);
22
55
  };
23
56
  }
57
+ /**
58
+ * @Value - Inject configuration value from environment or config
59
+ * Usage: @Value('${PORT}') private port: number;
60
+ * or: @Value('${DB_HOST:localhost}') private host: string;
61
+ */
24
62
  function Value(expression) {
25
63
  return (target, propertyKey) => {
26
64
  Reflect.defineMetadata(metadata_keys_1.METADATA_KEYS.VALUE, expression, target, propertyKey);
27
65
  };
28
66
  }
67
+ /**
68
+ * @Optional - Mark dependency as optional (won't throw if not found)
69
+ * Usage: @Optional() @Autowired() private service?: MyService;
70
+ */
71
+ function Optional() {
72
+ return (target, propertyKey) => {
73
+ Reflect.defineMetadata(metadata_keys_1.METADATA_KEYS.OPTIONAL, true, target, propertyKey);
74
+ };
75
+ }
76
+ /**
77
+ * @Lazy - Lazy load dependency (create on first access)
78
+ * Usage: @Lazy() @Autowired() private service: MyService;
79
+ */
80
+ function Lazy() {
81
+ return (target, propertyKey) => {
82
+ Reflect.defineMetadata(metadata_keys_1.METADATA_KEYS.LAZY, true, target, propertyKey);
83
+ const type = Reflect.getMetadata("design:type", target, propertyKey);
84
+ // Create a getter that resolves on first access
85
+ let cached = null;
86
+ let resolved = false;
87
+ Object.defineProperty(target, propertyKey, {
88
+ get() {
89
+ if (!resolved) {
90
+ const { DIContainer } = require("../container/di-container");
91
+ const container = DIContainer.getInstance();
92
+ cached = container.resolve(type);
93
+ resolved = true;
94
+ }
95
+ return cached;
96
+ },
97
+ enumerable: true,
98
+ configurable: true,
99
+ });
100
+ };
101
+ }
102
+ /**
103
+ * @PostConstruct - Method called after dependency injection is complete
104
+ * Usage: @PostConstruct() init() { ... }
105
+ */
106
+ function PostConstruct() {
107
+ return (target, propertyKey, descriptor) => {
108
+ Reflect.defineMetadata(metadata_keys_1.METADATA_KEYS.POST_CONSTRUCT, propertyKey, target.constructor);
109
+ };
110
+ }
111
+ /**
112
+ * @PreDestroy - Method called before bean is destroyed
113
+ * Usage: @PreDestroy() cleanup() { ... }
114
+ */
115
+ function PreDestroy() {
116
+ return (target, propertyKey, descriptor) => {
117
+ Reflect.defineMetadata(metadata_keys_1.METADATA_KEYS.PRE_DESTROY, propertyKey, target.constructor);
118
+ };
119
+ }
29
120
  //# sourceMappingURL=injection.decorators.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"injection.decorators.js","sourceRoot":"","sources":["../../../src/core/decorators/injection.decorators.ts"],"names":[],"mappings":";;AAEA,8BAKC;AAED,wBAIC;AAED,8BAIC;AAED,sBAIC;AAzBD,6DAA0D;AAE1D,SAAgB,SAAS;IACvB,OAAO,CAAC,MAAW,EAAE,WAA4B,EAAE,EAAE;QACnD,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,aAAa,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;QACrE,OAAO,CAAC,cAAc,CAAC,6BAAa,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IAC7E,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,MAAM,CAAC,KAAa;IAClC,OAAO,CAAC,MAAW,EAAE,WAA4B,EAAE,EAAE;QACnD,OAAO,CAAC,cAAc,CAAC,6BAAa,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3E,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,SAAS,CAAC,IAAY;IACpC,OAAO,CAAC,MAAW,EAAE,WAA4B,EAAE,EAAE;QACnD,OAAO,CAAC,cAAc,CAAC,6BAAa,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IAC7E,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,KAAK,CAAC,UAAkB;IACtC,OAAO,CAAC,MAAW,EAAE,WAA4B,EAAE,EAAE;QACnD,OAAO,CAAC,cAAc,CAAC,6BAAa,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IAC/E,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"injection.decorators.js","sourceRoot":"","sources":["../../../src/core/decorators/injection.decorators.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,32 @@
1
1
  export declare const METADATA_KEYS: {
2
- INJECTABLE: string;
3
- SCOPE: string;
4
- SERVICE: string;
5
- CONTROLLER: string;
6
- REPOSITORY: string;
7
- AUTO_CONFIGURATION: string;
8
- CONDITIONAL_ON_CLASS: string;
9
- CONDITIONAL_ON_MISSING_BEAN: string;
10
- CONDITIONAL_ON_PROPERTY: string;
11
- AUTOWIRED: string;
12
- INJECT: string;
13
- QUALIFIER: string;
14
- VALUE: string;
15
- HTTP_METHOD: string;
16
- ROUTE_PATH: string;
17
- PARAM_METADATA: string;
18
- APPLICATION: string;
2
+ readonly APPLICATION: "fragment:application";
3
+ readonly INJECTABLE: "fragment:injectable";
4
+ readonly CONTROLLER: "fragment:controller";
5
+ readonly SERVICE: "fragment:service";
6
+ readonly REPOSITORY: "fragment:repository";
7
+ readonly AUTO_CONFIGURATION: "fragment:auto-configuration";
8
+ readonly SCOPE: "fragment:scope";
9
+ readonly AUTOWIRED: "fragment:autowired";
10
+ readonly INJECT: "fragment:inject";
11
+ readonly INJECT_REPOSITORY: "fragment:inject-repository";
12
+ readonly QUALIFIER: "fragment:qualifier";
13
+ readonly VALUE: "fragment:value";
14
+ readonly OPTIONAL: "fragment:optional";
15
+ readonly LAZY: "fragment:lazy";
16
+ readonly HTTP_METHOD: "fragment:http-method";
17
+ readonly ROUTE_PATH: "fragment:route-path";
18
+ readonly POST_CONSTRUCT: "fragment:post-construct";
19
+ readonly PRE_DESTROY: "fragment:pre-destroy";
20
+ readonly PARAM_METADATA: "fragment:param-metadata";
21
+ readonly CONDITIONAL_ON_CLASS: "fragment:conditional-on-class";
22
+ readonly CONDITIONAL_ON_MISSING_BEAN: "fragment:conditional-on-missing-bean";
23
+ readonly CONDITIONAL_ON_PROPERTY: "fragment:conditional-on-property";
24
+ readonly CONDITIONAL_ON_BEAN: "fragment:conditional-on-bean";
25
+ readonly USE_GUARDS: "fragment:use-guards";
26
+ readonly USE_INTERCEPTORS: "fragment:use-interceptors";
27
+ readonly USE_FILTERS: "fragment:use-filters";
28
+ readonly VALIDATE: "fragment:validate";
29
+ readonly TRANSFORM: "fragment:transform";
19
30
  };
31
+ export type MetadataKey = (typeof METADATA_KEYS)[keyof typeof METADATA_KEYS];
20
32
  //# sourceMappingURL=metadata-keys.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"metadata-keys.d.ts","sourceRoot":"","sources":["../../../src/core/metadata/metadata-keys.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;CAkBzB,CAAC"}
1
+ {"version":3,"file":"metadata-keys.d.ts","sourceRoot":"","sources":["../../../src/core/metadata/metadata-keys.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0ChB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC"}
@@ -2,22 +2,40 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.METADATA_KEYS = void 0;
4
4
  exports.METADATA_KEYS = {
5
- INJECTABLE: 'fragment:injectable',
6
- SCOPE: 'fragment:scope',
7
- SERVICE: 'fragment:service',
8
- CONTROLLER: 'fragment:controller',
9
- REPOSITORY: 'fragment:repository',
10
- AUTO_CONFIGURATION: 'fragment:auto-configuration',
11
- CONDITIONAL_ON_CLASS: 'fragment:conditional-class',
12
- CONDITIONAL_ON_MISSING_BEAN: 'fragment:conditional-missing-bean',
13
- CONDITIONAL_ON_PROPERTY: 'fragment:conditional-property',
14
- AUTOWIRED: 'fragment:autowired',
15
- INJECT: 'fragment:inject',
16
- QUALIFIER: 'fragment:qualifier',
17
- VALUE: 'fragment:value',
18
- HTTP_METHOD: 'fragment:http-method',
19
- ROUTE_PATH: 'fragment:route-path',
20
- PARAM_METADATA: 'fragment:param-metadata',
21
- APPLICATION: 'fragment:application'
5
+ // Class decorators
6
+ APPLICATION: "fragment:application",
7
+ INJECTABLE: "fragment:injectable",
8
+ CONTROLLER: "fragment:controller",
9
+ SERVICE: "fragment:service",
10
+ REPOSITORY: "fragment:repository",
11
+ AUTO_CONFIGURATION: "fragment:auto-configuration",
12
+ SCOPE: "fragment:scope",
13
+ // Property decorators
14
+ AUTOWIRED: "fragment:autowired",
15
+ INJECT: "fragment:inject",
16
+ INJECT_REPOSITORY: "fragment:inject-repository",
17
+ QUALIFIER: "fragment:qualifier",
18
+ VALUE: "fragment:value",
19
+ OPTIONAL: "fragment:optional",
20
+ LAZY: "fragment:lazy",
21
+ // Method decorators
22
+ HTTP_METHOD: "fragment:http-method",
23
+ ROUTE_PATH: "fragment:route-path",
24
+ POST_CONSTRUCT: "fragment:post-construct",
25
+ PRE_DESTROY: "fragment:pre-destroy",
26
+ // Parameter decorators
27
+ PARAM_METADATA: "fragment:param-metadata",
28
+ // Conditional decorators
29
+ CONDITIONAL_ON_CLASS: "fragment:conditional-on-class",
30
+ CONDITIONAL_ON_MISSING_BEAN: "fragment:conditional-on-missing-bean",
31
+ CONDITIONAL_ON_PROPERTY: "fragment:conditional-on-property",
32
+ CONDITIONAL_ON_BEAN: "fragment:conditional-on-bean",
33
+ // Middleware & Guards
34
+ USE_GUARDS: "fragment:use-guards",
35
+ USE_INTERCEPTORS: "fragment:use-interceptors",
36
+ USE_FILTERS: "fragment:use-filters",
37
+ // Validation
38
+ VALIDATE: "fragment:validate",
39
+ TRANSFORM: "fragment:transform",
22
40
  };
23
41
  //# sourceMappingURL=metadata-keys.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"metadata-keys.js","sourceRoot":"","sources":["../../../src/core/metadata/metadata-keys.ts"],"names":[],"mappings":";;;AAAa,QAAA,aAAa,GAAG;IAC3B,UAAU,EAAE,qBAAqB;IACjC,KAAK,EAAE,gBAAgB;IACvB,OAAO,EAAE,kBAAkB;IAC3B,UAAU,EAAE,qBAAqB;IACjC,UAAU,EAAE,qBAAqB;IACjC,kBAAkB,EAAE,6BAA6B;IACjD,oBAAoB,EAAE,4BAA4B;IAClD,2BAA2B,EAAE,mCAAmC;IAChE,uBAAuB,EAAE,+BAA+B;IACxD,SAAS,EAAE,oBAAoB;IAC/B,MAAM,EAAE,iBAAiB;IACzB,SAAS,EAAE,oBAAoB;IAC/B,KAAK,EAAE,gBAAgB;IACvB,WAAW,EAAE,sBAAsB;IACnC,UAAU,EAAE,qBAAqB;IACjC,cAAc,EAAE,yBAAyB;IACzC,WAAW,EAAE,sBAAsB;CACpC,CAAC"}
1
+ {"version":3,"file":"metadata-keys.js","sourceRoot":"","sources":["../../../src/core/metadata/metadata-keys.ts"],"names":[],"mappings":";;;AAAa,QAAA,aAAa,GAAG;IAC3B,mBAAmB;IACnB,WAAW,EAAE,sBAAsB;IACnC,UAAU,EAAE,qBAAqB;IACjC,UAAU,EAAE,qBAAqB;IACjC,OAAO,EAAE,kBAAkB;IAC3B,UAAU,EAAE,qBAAqB;IACjC,kBAAkB,EAAE,6BAA6B;IACjD,KAAK,EAAE,gBAAgB;IAEvB,sBAAsB;IACtB,SAAS,EAAE,oBAAoB;IAC/B,MAAM,EAAE,iBAAiB;IACzB,iBAAiB,EAAE,4BAA4B;IAC/C,SAAS,EAAE,oBAAoB;IAC/B,KAAK,EAAE,gBAAgB;IACvB,QAAQ,EAAE,mBAAmB;IAC7B,IAAI,EAAE,eAAe;IAErB,oBAAoB;IACpB,WAAW,EAAE,sBAAsB;IACnC,UAAU,EAAE,qBAAqB;IACjC,cAAc,EAAE,yBAAyB;IACzC,WAAW,EAAE,sBAAsB;IAEnC,uBAAuB;IACvB,cAAc,EAAE,yBAAyB;IAEzC,yBAAyB;IACzB,oBAAoB,EAAE,+BAA+B;IACrD,2BAA2B,EAAE,sCAAsC;IACnE,uBAAuB,EAAE,kCAAkC;IAC3D,mBAAmB,EAAE,8BAA8B;IAEnD,sBAAsB;IACtB,UAAU,EAAE,qBAAqB;IACjC,gBAAgB,EAAE,2BAA2B;IAC7C,WAAW,EAAE,sBAAsB;IAEnC,aAAa;IACb,QAAQ,EAAE,mBAAmB;IAC7B,SAAS,EAAE,oBAAoB;CACvB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fragment-ts",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "description": "Spring Boot-style framework for TypeScript with Express and TypeORM",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -169,12 +169,14 @@ export class InitCommand {
169
169
  "migrate:revert": "fragment migrate:revert",
170
170
  },
171
171
  dependencies: {
172
- "fragment-ts": "^1.0.17",
172
+ "fragment-ts": "^1.0.18",
173
173
  "reflect-metadata": "^0.1.13",
174
174
  },
175
175
  devDependencies: {
176
176
  typescript: "^5.3.3",
177
177
  "@types/node": "^20.10.5",
178
+ "ts-node": "^10.9.2",
179
+ "tsconfig-paths": "^4.2.0",
178
180
  },
179
181
  };
180
182
 
@@ -214,9 +216,7 @@ export class InitCommand {
214
216
  database: process.env.DATABASE_FILE || "database.sqlite",
215
217
  synchronize: true,
216
218
  logging: false,
217
- entities: isProd
218
- ? ["dist/**/*.entity.js"]
219
- : ["src/**/*.entity.ts"],
219
+ entities: isProd ? ["dist/**/*.entity.js"] : ["src/**/*.entity.ts"],
220
220
  migrations: isProd
221
221
  ? ["dist/migrations/**/*.js"]
222
222
  : ["src/migrations/**/*.ts"],
@@ -0,0 +1,289 @@
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import * as path from "path";
4
+ import { spawn } from "child_process";
5
+ import * as fs from "fs";
6
+
7
+ export class TestCommand {
8
+ static register(program: Command): void {
9
+ program
10
+ .command("test")
11
+ .description("Run tests")
12
+ .option("--watch", "Run tests in watch mode")
13
+ .option(
14
+ "--env <environment>",
15
+ "Environment mode: dev (use src/) or prod (use dist/)",
16
+ "auto",
17
+ )
18
+ .option("--pattern <pattern>", "Test file pattern", "**/*.spec.ts")
19
+ .option("--coverage", "Generate coverage report")
20
+ .action(async (options) => {
21
+ await this.runTests(options);
22
+ });
23
+ }
24
+
25
+ private static async runTests(options: any): Promise<void> {
26
+ console.log(chalk.blue("\n🧪 Running Fragment Tests...\n"));
27
+
28
+ const cwd = process.cwd();
29
+ const hasSource = fs.existsSync(path.join(cwd, "src"));
30
+ const hasDist = fs.existsSync(path.join(cwd, "dist"));
31
+
32
+ let useTypeScript: boolean;
33
+ let mode: string;
34
+ let basePath: string;
35
+ let pattern: string;
36
+
37
+ if (options.env === "dev") {
38
+ if (!hasSource) {
39
+ console.log(
40
+ chalk.red("Development mode requested but src/ directory not found"),
41
+ );
42
+ return;
43
+ }
44
+ useTypeScript = true;
45
+ mode = "development (src/)";
46
+ basePath = "src";
47
+ pattern = options.pattern || "**/*.spec.ts";
48
+ } else if (options.env === "prod") {
49
+ if (!hasDist) {
50
+ console.log(
51
+ chalk.red(
52
+ "Production mode requested but dist/ directory not found. Run: fragment build",
53
+ ),
54
+ );
55
+ return;
56
+ }
57
+ useTypeScript = false;
58
+ mode = "production (dist/)";
59
+ basePath = "dist";
60
+ pattern = options.pattern.replace(".ts", ".js") || "**/*.spec.js";
61
+ } else {
62
+ // Auto-detect
63
+ if (hasSource) {
64
+ useTypeScript = true;
65
+ mode = "auto-detected development (src/)";
66
+ basePath = "src";
67
+ pattern = options.pattern || "**/*.spec.ts";
68
+ } else if (hasDist) {
69
+ useTypeScript = false;
70
+ mode = "auto-detected production (dist/)";
71
+ basePath = "dist";
72
+ pattern = options.pattern.replace(".ts", ".js") || "**/*.spec.js";
73
+ } else {
74
+ console.log(
75
+ chalk.red("No src/ or dist/ directory found. Run: fragment init"),
76
+ );
77
+ return;
78
+ }
79
+ }
80
+
81
+ console.log(chalk.gray(` Mode: ${mode}\n`));
82
+
83
+ const scriptContent = `
84
+ ${useTypeScript ? "require('ts-node/register/transpile-only');" : ""}
85
+ require('reflect-metadata');
86
+
87
+ const { glob } = require('glob');
88
+ const path = require('path');
89
+
90
+ // Global test state
91
+ const testState = {
92
+ suites: [],
93
+ currentSuite: null,
94
+ passed: 0,
95
+ failed: 0,
96
+ errors: []
97
+ };
98
+
99
+ // Global test functions
100
+ global.describe = function(name, fn) {
101
+ const suite = { name, tests: [] };
102
+ testState.suites.push(suite);
103
+ testState.currentSuite = suite;
104
+ fn();
105
+ testState.currentSuite = null;
106
+ };
107
+
108
+ global.it = function(name, fn) {
109
+ if (!testState.currentSuite) {
110
+ throw new Error('it() must be called inside describe()');
111
+ }
112
+ testState.currentSuite.tests.push({ name, fn });
113
+ };
114
+
115
+ global.expect = function(actual) {
116
+ return {
117
+ toBe(expected) {
118
+ if (actual !== expected) {
119
+ throw new Error(\`Expected \${actual} to be \${expected}\`);
120
+ }
121
+ },
122
+ toEqual(expected) {
123
+ if (JSON.stringify(actual) !== JSON.stringify(expected)) {
124
+ throw new Error(\`Expected \${JSON.stringify(actual)} to equal \${JSON.stringify(expected)}\`);
125
+ }
126
+ },
127
+ toBeTruthy() {
128
+ if (!actual) {
129
+ throw new Error(\`Expected \${actual} to be truthy\`);
130
+ }
131
+ },
132
+ toBeFalsy() {
133
+ if (actual) {
134
+ throw new Error(\`Expected \${actual} to be falsy\`);
135
+ }
136
+ },
137
+ toThrow(expectedError) {
138
+ let threw = false;
139
+ let error = null;
140
+ try {
141
+ actual();
142
+ } catch (e) {
143
+ threw = true;
144
+ error = e;
145
+ }
146
+ if (!threw) {
147
+ throw new Error('Expected function to throw');
148
+ }
149
+ if (expectedError && error.message !== expectedError) {
150
+ throw new Error(\`Expected error message "\${expectedError}" but got "\${error.message}"\`);
151
+ }
152
+ },
153
+ toBeInstanceOf(expected) {
154
+ if (!(actual instanceof expected)) {
155
+ throw new Error(\`Expected \${actual} to be instance of \${expected.name}\`);
156
+ }
157
+ },
158
+ toContain(expected) {
159
+ if (!actual.includes(expected)) {
160
+ throw new Error(\`Expected \${actual} to contain \${expected}\`);
161
+ }
162
+ },
163
+ toHaveProperty(property, value) {
164
+ if (!(property in actual)) {
165
+ throw new Error(\`Expected object to have property \${property}\`);
166
+ }
167
+ if (value !== undefined && actual[property] !== value) {
168
+ throw new Error(\`Expected property \${property} to be \${value} but got \${actual[property]}\`);
169
+ }
170
+ },
171
+ toBeNull() {
172
+ if (actual !== null) {
173
+ throw new Error(\`Expected \${actual} to be null\`);
174
+ }
175
+ },
176
+ toBeUndefined() {
177
+ if (actual !== undefined) {
178
+ throw new Error(\`Expected \${actual} to be undefined\`);
179
+ }
180
+ },
181
+ toHaveLength(expected) {
182
+ if (actual.length !== expected) {
183
+ throw new Error(\`Expected length \${expected} but got \${actual.length}\`);
184
+ }
185
+ }
186
+ };
187
+ };
188
+
189
+ async function runTests() {
190
+ try {
191
+ // Find and load test files
192
+ const files = await glob('${basePath}/${pattern}', { cwd: process.cwd() });
193
+
194
+ if (files.length === 0) {
195
+ console.log('No test files found matching pattern: ${basePath}/${pattern}');
196
+ process.exit(0);
197
+ }
198
+
199
+ console.log(\`Found \${files.length} test file(s)\\n\`);
200
+
201
+ // Load all test files
202
+ for (const file of files) {
203
+ require(path.resolve(file));
204
+ }
205
+
206
+ // Run all tests
207
+ for (const suite of testState.suites) {
208
+ console.log(\`\\nšŸ“¦ \${suite.name}\`);
209
+
210
+ for (const test of suite.tests) {
211
+ try {
212
+ await test.fn();
213
+ console.log(\` āœ“ \${test.name}\`);
214
+ testState.passed++;
215
+ } catch (error) {
216
+ console.log(\` āœ— \${test.name}\`);
217
+ console.error(\` \${error.message}\`);
218
+ testState.failed++;
219
+ testState.errors.push({
220
+ suite: suite.name,
221
+ test: test.name,
222
+ error: error.message,
223
+ stack: error.stack
224
+ });
225
+ }
226
+ }
227
+ }
228
+
229
+ // Print summary
230
+ console.log(\`\\n\\nšŸ“Š Results: \${testState.passed} passed, \${testState.failed} failed\\n\`);
231
+
232
+ if (testState.failed > 0) {
233
+ console.log('\\nāŒ Failed Tests:\\n');
234
+ testState.errors.forEach(err => {
235
+ console.log(\` \${err.suite} > \${err.test}\`);
236
+ console.log(\` \${err.error}\\n\`);
237
+ });
238
+ process.exit(1);
239
+ } else {
240
+ console.log('āœ… All tests passed!\\n');
241
+ process.exit(0);
242
+ }
243
+ } catch (error) {
244
+ console.error('Error running tests:', error);
245
+ process.exit(1);
246
+ }
247
+ }
248
+
249
+ runTests();
250
+ `;
251
+
252
+ const scriptPath = path.join(cwd, ".fragment-test-runner.js");
253
+
254
+ try {
255
+ fs.writeFileSync(scriptPath, scriptContent);
256
+
257
+ const nodeArgs = [scriptPath];
258
+ const env = {
259
+ ...process.env,
260
+ TS_NODE_TRANSPILE_ONLY: "true",
261
+ NODE_ENV: "test",
262
+ };
263
+
264
+ const proc = spawn("node", nodeArgs, {
265
+ cwd,
266
+ stdio: "inherit",
267
+ env,
268
+ });
269
+
270
+ proc.on("close", (code) => {
271
+ try {
272
+ fs.unlinkSync(scriptPath);
273
+ } catch {}
274
+ process.exit(code || 0);
275
+ });
276
+
277
+ proc.on("error", (error) => {
278
+ console.error(chalk.red("Failed to run tests:"), error);
279
+ try {
280
+ fs.unlinkSync(scriptPath);
281
+ } catch {}
282
+ process.exit(1);
283
+ });
284
+ } catch (error: any) {
285
+ console.error(chalk.red("Failed to create test runner:"), error.message);
286
+ process.exit(1);
287
+ }
288
+ }
289
+ }
package/src/cli/index.ts CHANGED
@@ -1,23 +1,28 @@
1
- import { Command } from 'commander';
2
- import { InitCommand } from './commands/init.command';
3
- import { GenerateCommand } from './commands/generate.command';
4
- import { ServeCommand } from './commands/serve.command';
5
- import { BuildCommand } from './commands/build.command';
6
- import { MigrateCommand } from './commands/migrate.command';
7
- import { DiagnosticsCommand } from './commands/diagnostics.command';
1
+ import { Command } from "commander";
2
+ import { InitCommand } from "./commands/init.command";
3
+ import { GenerateCommand } from "./commands/generate.command";
4
+ import { ServeCommand } from "./commands/serve.command";
5
+ import { BuildCommand } from "./commands/build.command";
6
+ import { MigrateCommand } from "./commands/migrate.command";
7
+ import { DiagnosticsCommand } from "./commands/diagnostics.command";
8
+ import { TestCommand } from "./commands/test.command";
8
9
 
9
10
  const program = new Command();
10
11
 
11
12
  program
12
- .name('fragment')
13
- .description('Fragment Framework CLI')
14
- .version('1.0.0');
13
+ .name("fragment")
14
+ .description(
15
+ "Fragment Framework CLI - A TypeScript framework inspired by Spring Boot",
16
+ )
17
+ .version("1.0.0");
15
18
 
19
+ // Register all commands
16
20
  InitCommand.register(program);
17
21
  GenerateCommand.register(program);
18
22
  ServeCommand.register(program);
19
23
  BuildCommand.register(program);
24
+ TestCommand.register(program);
20
25
  MigrateCommand.register(program);
21
26
  DiagnosticsCommand.register(program);
22
27
 
23
- program.parse();
28
+ program.parse();