motia 0.7.2-beta.134 → 0.7.2-beta.135-604391

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 (183) hide show
  1. package/dist/cjs/cloud/build/builders/python/index.d.ts +0 -1
  2. package/dist/cjs/cloud/build/builders/python/index.js +10 -15
  3. package/dist/cjs/cloud/build/builders/python/python-data/__tests__/extract-python-data.test.js +4 -5
  4. package/dist/cjs/cloud/build/builders/python/python-data/__tests__/get-dependencies-from-file.test.js +3 -9
  5. package/dist/cjs/cloud/build/builders/python/python-data/__tests__/read-requirements.test.js +7 -29
  6. package/dist/cjs/cloud/build/builders/python/python-data/__tests__/resolve-dep-name.test.js +19 -10
  7. package/dist/cjs/cloud/build/builders/python/python-data/extract-python-data.d.ts +1 -1
  8. package/dist/cjs/cloud/build/builders/python/python-data/extract-python-data.js +3 -3
  9. package/dist/cjs/cloud/build/builders/python/python-data/get-dependencies-from-file.d.ts +1 -2
  10. package/dist/cjs/cloud/build/builders/python/python-data/get-dependencies-from-file.js +2 -2
  11. package/dist/cjs/cloud/build/builders/python/python-data/read-requirements.d.ts +8 -10
  12. package/dist/cjs/cloud/build/builders/python/python-data/read-requirements.js +3 -3
  13. package/dist/cjs/cloud/build/builders/python/python-data/{resolve-dep-name.d.ts → resolve-dep-names.d.ts} +2 -2
  14. package/dist/cjs/cloud/build/builders/python/python-data/{resolve-dep-name.js → resolve-dep-names.js} +4 -5
  15. package/dist/cjs/cloud/build/builders/python/python-data/traverse-tree.d.ts +1 -2
  16. package/dist/cjs/cloud/build/builders/python/python-data/traverse-tree.js +4 -4
  17. package/dist/cjs/create/templates/generate.js +2 -2
  18. package/dist/cjs/create/templates/generate.ts +2 -2
  19. package/dist/cjs/create/templates/nodejs/.cursor/architecture/database/database-migration.mdc +49 -0
  20. package/dist/cjs/create/templates/nodejs/.cursor/architecture/database/database.mdc +83 -0
  21. package/dist/cjs/create/templates/nodejs/src/services/pet-store/create-order.ts.txt +15 -0
  22. package/dist/cjs/create/templates/nodejs/src/services/pet-store/create-pet.ts.txt +14 -0
  23. package/dist/cjs/create/templates/nodejs/src/services/pet-store/index.ts.txt +9 -0
  24. package/dist/cjs/create/templates/nodejs/steps/{api.step.ts-features.json.txt → petstore/api.step.ts-features.json.txt} +9 -9
  25. package/dist/cjs/create/templates/nodejs/steps/{api.step.ts.txt → petstore/api.step.ts.txt} +1 -2
  26. package/dist/{esm/create/templates/nodejs/steps → cjs/create/templates/nodejs/steps/petstore}/process-food-order.step.ts.txt +1 -1
  27. package/dist/cjs/cursor-rules/dot-files/.cursor/architecture/architecture.mdc +96 -0
  28. package/dist/cjs/cursor-rules/dot-files/.cursor/architecture/error-handling.mdc +122 -0
  29. package/dist/cjs/cursor-rules/dot-files/.cursor/index.mdc +26 -0
  30. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/api-steps.mdc +317 -0
  31. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/cron-steps.mdc +144 -0
  32. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/event-steps.mdc +157 -0
  33. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/middlewares.mdc +122 -0
  34. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/realtime-streaming.mdc +231 -0
  35. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/state-management.mdc +73 -0
  36. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/ui-steps.mdc +76 -0
  37. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/virtual-steps.mdc +172 -0
  38. package/dist/esm/cloud/build/builders/python/index.d.ts +0 -1
  39. package/dist/esm/cloud/build/builders/python/index.js +10 -15
  40. package/dist/esm/cloud/build/builders/python/python-data/__tests__/extract-python-data.test.js +4 -5
  41. package/dist/esm/cloud/build/builders/python/python-data/__tests__/get-dependencies-from-file.test.js +3 -9
  42. package/dist/esm/cloud/build/builders/python/python-data/__tests__/read-requirements.test.js +7 -29
  43. package/dist/esm/cloud/build/builders/python/python-data/__tests__/resolve-dep-name.test.js +16 -7
  44. package/dist/esm/cloud/build/builders/python/python-data/extract-python-data.d.ts +1 -1
  45. package/dist/esm/cloud/build/builders/python/python-data/extract-python-data.js +3 -3
  46. package/dist/esm/cloud/build/builders/python/python-data/get-dependencies-from-file.d.ts +1 -2
  47. package/dist/esm/cloud/build/builders/python/python-data/get-dependencies-from-file.js +2 -2
  48. package/dist/esm/cloud/build/builders/python/python-data/read-requirements.d.ts +8 -10
  49. package/dist/esm/cloud/build/builders/python/python-data/read-requirements.js +3 -3
  50. package/dist/esm/cloud/build/builders/python/python-data/{resolve-dep-name.d.ts → resolve-dep-names.d.ts} +2 -2
  51. package/dist/esm/cloud/build/builders/python/python-data/{resolve-dep-name.js → resolve-dep-names.js} +4 -5
  52. package/dist/esm/cloud/build/builders/python/python-data/traverse-tree.d.ts +1 -2
  53. package/dist/esm/cloud/build/builders/python/python-data/traverse-tree.js +4 -4
  54. package/dist/esm/create/templates/generate.js +2 -2
  55. package/dist/esm/create/templates/generate.ts +2 -2
  56. package/dist/esm/create/templates/nodejs/.cursor/architecture/database/database-migration.mdc +49 -0
  57. package/dist/esm/create/templates/nodejs/.cursor/architecture/database/database.mdc +83 -0
  58. package/dist/esm/create/templates/nodejs/src/services/pet-store/create-order.ts.txt +15 -0
  59. package/dist/esm/create/templates/nodejs/src/services/pet-store/create-pet.ts.txt +14 -0
  60. package/dist/esm/create/templates/nodejs/src/services/pet-store/index.ts.txt +9 -0
  61. package/dist/esm/create/templates/nodejs/steps/{api.step.ts-features.json.txt → petstore/api.step.ts-features.json.txt} +9 -9
  62. package/dist/esm/create/templates/nodejs/steps/{api.step.ts.txt → petstore/api.step.ts.txt} +1 -2
  63. package/dist/{cjs/create/templates/nodejs/steps → esm/create/templates/nodejs/steps/petstore}/process-food-order.step.ts.txt +1 -1
  64. package/dist/esm/cursor-rules/dot-files/.cursor/architecture/architecture.mdc +96 -0
  65. package/dist/esm/cursor-rules/dot-files/.cursor/architecture/error-handling.mdc +122 -0
  66. package/dist/esm/cursor-rules/dot-files/.cursor/index.mdc +26 -0
  67. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/api-steps.mdc +317 -0
  68. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/cron-steps.mdc +144 -0
  69. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/event-steps.mdc +157 -0
  70. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/middlewares.mdc +122 -0
  71. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/realtime-streaming.mdc +231 -0
  72. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/state-management.mdc +73 -0
  73. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/ui-steps.mdc +76 -0
  74. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/virtual-steps.mdc +172 -0
  75. package/dist/types/cloud/build/builders/python/index.d.ts +0 -1
  76. package/dist/types/cloud/build/builders/python/python-data/extract-python-data.d.ts +1 -1
  77. package/dist/types/cloud/build/builders/python/python-data/get-dependencies-from-file.d.ts +1 -2
  78. package/dist/types/cloud/build/builders/python/python-data/read-requirements.d.ts +8 -10
  79. package/dist/types/cloud/build/builders/python/python-data/{resolve-dep-name.d.ts → resolve-dep-names.d.ts} +2 -2
  80. package/dist/types/cloud/build/builders/python/python-data/traverse-tree.d.ts +1 -2
  81. package/package.json +4 -4
  82. package/dist/cjs/create/templates/nodejs/services/pet-store.ts.txt +0 -29
  83. package/dist/cjs/cursor-rules/dot-files/.claude/CLAUDE.md +0 -467
  84. package/dist/cjs/cursor-rules/dot-files/.claude/README.md +0 -97
  85. package/dist/cjs/cursor-rules/dot-files/.claude/agents/code-reviewer.md +0 -153
  86. package/dist/cjs/cursor-rules/dot-files/.claude/agents/debugger.md +0 -259
  87. package/dist/cjs/cursor-rules/dot-files/.claude/agents/test-runner.md +0 -268
  88. package/dist/cjs/cursor-rules/dot-files/.claude/commands/add-authentication.md +0 -491
  89. package/dist/cjs/cursor-rules/dot-files/.claude/commands/ai-ml-patterns.md +0 -748
  90. package/dist/cjs/cursor-rules/dot-files/.claude/commands/authentication.md +0 -515
  91. package/dist/cjs/cursor-rules/dot-files/.claude/commands/backend-types.md +0 -719
  92. package/dist/cjs/cursor-rules/dot-files/.claude/commands/build-api.md +0 -407
  93. package/dist/cjs/cursor-rules/dot-files/.claude/commands/claude-workflows.md +0 -1032
  94. package/dist/cjs/cursor-rules/dot-files/.claude/commands/complete-backend.md +0 -345
  95. package/dist/cjs/cursor-rules/dot-files/.claude/commands/create-api.md +0 -96
  96. package/dist/cjs/cursor-rules/dot-files/.claude/commands/data-processing.md +0 -977
  97. package/dist/cjs/cursor-rules/dot-files/.claude/commands/integrate-ai.md +0 -852
  98. package/dist/cjs/cursor-rules/dot-files/.claude/commands/javascript-patterns.md +0 -678
  99. package/dist/cjs/cursor-rules/dot-files/.claude/commands/multi-language-workflow.md +0 -756
  100. package/dist/cjs/cursor-rules/dot-files/.claude/commands/multi-language.md +0 -141
  101. package/dist/cjs/cursor-rules/dot-files/.claude/commands/process-background-jobs.md +0 -587
  102. package/dist/cjs/cursor-rules/dot-files/.claude/commands/process-events.md +0 -89
  103. package/dist/cjs/cursor-rules/dot-files/.claude/hooks/pre-commit.sh +0 -84
  104. package/dist/cjs/cursor-rules/dot-files/.claude/settings.json +0 -37
  105. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/ai-agent-patterns.mdc +0 -725
  106. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/api-design-patterns.mdc +0 -740
  107. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/api-steps.mdc +0 -230
  108. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/architecture.mdc +0 -189
  109. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/authentication-patterns.mdc +0 -620
  110. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/background-job-patterns.mdc +0 -628
  111. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/complete-application-patterns.mdc +0 -433
  112. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/complete-backend-generator.mdc +0 -415
  113. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/cron-steps.mdc +0 -257
  114. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/event-steps.mdc +0 -504
  115. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/instructions.mdc +0 -15
  116. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/multi-language-workflows.mdc +0 -1059
  117. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/noop-steps.mdc +0 -57
  118. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/production-deployment.mdc +0 -668
  119. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/realtime-streaming.mdc +0 -656
  120. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/state-management.mdc +0 -371
  121. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/steps.mdc +0 -373
  122. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/testing.mdc +0 -329
  123. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/typescript.mdc +0 -409
  124. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/ui-steps.mdc +0 -429
  125. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/workflow-patterns.mdc +0 -938
  126. package/dist/cjs/cursor-rules/dot-files/AGENTS.md +0 -397
  127. package/dist/cjs/cursor-rules/dot-files/README.md +0 -58
  128. package/dist/esm/create/templates/nodejs/services/pet-store.ts.txt +0 -29
  129. package/dist/esm/cursor-rules/dot-files/.claude/CLAUDE.md +0 -467
  130. package/dist/esm/cursor-rules/dot-files/.claude/README.md +0 -97
  131. package/dist/esm/cursor-rules/dot-files/.claude/agents/code-reviewer.md +0 -153
  132. package/dist/esm/cursor-rules/dot-files/.claude/agents/debugger.md +0 -259
  133. package/dist/esm/cursor-rules/dot-files/.claude/agents/test-runner.md +0 -268
  134. package/dist/esm/cursor-rules/dot-files/.claude/commands/add-authentication.md +0 -491
  135. package/dist/esm/cursor-rules/dot-files/.claude/commands/ai-ml-patterns.md +0 -748
  136. package/dist/esm/cursor-rules/dot-files/.claude/commands/authentication.md +0 -515
  137. package/dist/esm/cursor-rules/dot-files/.claude/commands/backend-types.md +0 -719
  138. package/dist/esm/cursor-rules/dot-files/.claude/commands/build-api.md +0 -407
  139. package/dist/esm/cursor-rules/dot-files/.claude/commands/claude-workflows.md +0 -1032
  140. package/dist/esm/cursor-rules/dot-files/.claude/commands/complete-backend.md +0 -345
  141. package/dist/esm/cursor-rules/dot-files/.claude/commands/create-api.md +0 -96
  142. package/dist/esm/cursor-rules/dot-files/.claude/commands/data-processing.md +0 -977
  143. package/dist/esm/cursor-rules/dot-files/.claude/commands/integrate-ai.md +0 -852
  144. package/dist/esm/cursor-rules/dot-files/.claude/commands/javascript-patterns.md +0 -678
  145. package/dist/esm/cursor-rules/dot-files/.claude/commands/multi-language-workflow.md +0 -756
  146. package/dist/esm/cursor-rules/dot-files/.claude/commands/multi-language.md +0 -141
  147. package/dist/esm/cursor-rules/dot-files/.claude/commands/process-background-jobs.md +0 -587
  148. package/dist/esm/cursor-rules/dot-files/.claude/commands/process-events.md +0 -89
  149. package/dist/esm/cursor-rules/dot-files/.claude/hooks/pre-commit.sh +0 -84
  150. package/dist/esm/cursor-rules/dot-files/.claude/settings.json +0 -37
  151. package/dist/esm/cursor-rules/dot-files/.cursor/rules/ai-agent-patterns.mdc +0 -725
  152. package/dist/esm/cursor-rules/dot-files/.cursor/rules/api-design-patterns.mdc +0 -740
  153. package/dist/esm/cursor-rules/dot-files/.cursor/rules/api-steps.mdc +0 -230
  154. package/dist/esm/cursor-rules/dot-files/.cursor/rules/architecture.mdc +0 -189
  155. package/dist/esm/cursor-rules/dot-files/.cursor/rules/authentication-patterns.mdc +0 -620
  156. package/dist/esm/cursor-rules/dot-files/.cursor/rules/background-job-patterns.mdc +0 -628
  157. package/dist/esm/cursor-rules/dot-files/.cursor/rules/complete-application-patterns.mdc +0 -433
  158. package/dist/esm/cursor-rules/dot-files/.cursor/rules/complete-backend-generator.mdc +0 -415
  159. package/dist/esm/cursor-rules/dot-files/.cursor/rules/cron-steps.mdc +0 -257
  160. package/dist/esm/cursor-rules/dot-files/.cursor/rules/event-steps.mdc +0 -504
  161. package/dist/esm/cursor-rules/dot-files/.cursor/rules/instructions.mdc +0 -15
  162. package/dist/esm/cursor-rules/dot-files/.cursor/rules/multi-language-workflows.mdc +0 -1059
  163. package/dist/esm/cursor-rules/dot-files/.cursor/rules/noop-steps.mdc +0 -57
  164. package/dist/esm/cursor-rules/dot-files/.cursor/rules/production-deployment.mdc +0 -668
  165. package/dist/esm/cursor-rules/dot-files/.cursor/rules/realtime-streaming.mdc +0 -656
  166. package/dist/esm/cursor-rules/dot-files/.cursor/rules/state-management.mdc +0 -371
  167. package/dist/esm/cursor-rules/dot-files/.cursor/rules/steps.mdc +0 -373
  168. package/dist/esm/cursor-rules/dot-files/.cursor/rules/testing.mdc +0 -329
  169. package/dist/esm/cursor-rules/dot-files/.cursor/rules/typescript.mdc +0 -409
  170. package/dist/esm/cursor-rules/dot-files/.cursor/rules/ui-steps.mdc +0 -429
  171. package/dist/esm/cursor-rules/dot-files/.cursor/rules/workflow-patterns.mdc +0 -938
  172. package/dist/esm/cursor-rules/dot-files/AGENTS.md +0 -397
  173. package/dist/esm/cursor-rules/dot-files/README.md +0 -58
  174. /package/dist/cjs/create/templates/nodejs/{services → src/services/pet-store}/types.ts.txt +0 -0
  175. /package/dist/cjs/create/templates/nodejs/steps/{notification.step.ts.txt → petstore/notification.step.ts.txt} +0 -0
  176. /package/dist/cjs/create/templates/nodejs/steps/{process-food-order.step.ts-features.json.txt → petstore/process-food-order.step.ts-features.json.txt} +0 -0
  177. /package/dist/cjs/create/templates/nodejs/steps/{state-audit-cron.step.ts-features.json.txt → petstore/state-audit-cron.step.ts-features.json.txt} +0 -0
  178. /package/dist/cjs/create/templates/nodejs/steps/{state-audit-cron.step.ts.txt → petstore/state-audit-cron.step.ts.txt} +0 -0
  179. /package/dist/esm/create/templates/nodejs/{services → src/services/pet-store}/types.ts.txt +0 -0
  180. /package/dist/esm/create/templates/nodejs/steps/{notification.step.ts.txt → petstore/notification.step.ts.txt} +0 -0
  181. /package/dist/esm/create/templates/nodejs/steps/{process-food-order.step.ts-features.json.txt → petstore/process-food-order.step.ts-features.json.txt} +0 -0
  182. /package/dist/esm/create/templates/nodejs/steps/{state-audit-cron.step.ts-features.json.txt → petstore/state-audit-cron.step.ts-features.json.txt} +0 -0
  183. /package/dist/esm/create/templates/nodejs/steps/{state-audit-cron.step.ts.txt → petstore/state-audit-cron.step.ts.txt} +0 -0
@@ -6,7 +6,6 @@ export declare class PythonBuilder implements StepBuilder {
6
6
  private readonly listener;
7
7
  private packager;
8
8
  constructor(builder: Builder, listener: BuildListener);
9
- private getRequirements;
10
9
  buildApiSteps(steps: Step<ApiRouteConfig>[]): Promise<RouterBuildResult>;
11
10
  build(step: Step): Promise<void>;
12
11
  private generatePackage;
@@ -12,7 +12,7 @@ const archiver_1 = require("../archiver");
12
12
  const include_static_files_1 = require("../include-static-files");
13
13
  const extract_python_data_1 = require("./python-data/extract-python-data");
14
14
  const read_requirements_1 = require("./python-data/read-requirements");
15
- const resolve_dep_name_1 = require("./python-data/resolve-dep-name");
15
+ const resolve_dep_names_1 = require("./python-data/resolve-dep-names");
16
16
  const uv_packager_1 = require("./uv-packager");
17
17
  class PythonBuilder {
18
18
  constructor(builder, listener) {
@@ -21,17 +21,6 @@ class PythonBuilder {
21
21
  (0, activate_python_env_1.activatePythonVenv)({ baseDir: this.builder.projectDir });
22
22
  this.packager = new uv_packager_1.UvPackager();
23
23
  }
24
- getRequirements() {
25
- const requirementsFile = path_1.default.join(this.builder.projectDir, 'requirements.txt');
26
- const depNames = Object.keys((0, read_requirements_1.readRequirements)(requirementsFile, (name) => ({ name, importName: name })));
27
- const sitePackagesPath = (0, activate_python_env_1.getSitePackagesPath)({ baseDir: this.builder.projectDir });
28
- const mapper = (0, resolve_dep_name_1.resolveDepNames)(depNames, sitePackagesPath);
29
- const describer = (name) => {
30
- const [, to] = mapper.find(([from]) => from === name) ?? [];
31
- return { name, importName: to ?? name };
32
- };
33
- return (0, read_requirements_1.readRequirements)(requirementsFile, describer);
34
- }
35
24
  async buildApiSteps(steps) {
36
25
  const zipName = 'router-python.zip';
37
26
  const archive = new archiver_1.Archiver(path_1.default.join(constants_1.distDir, zipName));
@@ -79,8 +68,11 @@ class PythonBuilder {
79
68
  }
80
69
  }
81
70
  async generatePackage(bundleDir, entrypointPath, archive, fileContent) {
82
- const requirements = this.getRequirements();
83
- const { externalDependencies, files } = (0, extract_python_data_1.extractPythonData)(this.builder.projectDir, entrypointPath, requirements, fileContent);
71
+ const requirementsFile = path_1.default.join(this.builder.projectDir, 'requirements.txt');
72
+ const requirements = (0, read_requirements_1.readRequirements)(requirementsFile);
73
+ const sitePackagesPath = (0, activate_python_env_1.getSitePackagesPath)({ baseDir: this.builder.projectDir });
74
+ const dependenciesMap = (0, resolve_dep_names_1.resolveDepNames)(Object.keys(requirements), sitePackagesPath);
75
+ const { externalDependencies, files } = (0, extract_python_data_1.extractPythonData)(this.builder.projectDir, entrypointPath, dependenciesMap, fileContent);
84
76
  // move files
85
77
  for (const file of files) {
86
78
  fs_1.default.mkdirSync(path_1.default.dirname(path_1.default.join(bundleDir, file)), { recursive: true });
@@ -94,7 +86,10 @@ class PythonBuilder {
94
86
  const dependencies = Object.values(externalDependencies);
95
87
  if (dependencies.length > 0) {
96
88
  // create requirements.txt
97
- fs_1.default.writeFileSync(path_1.default.join(bundleDir, 'requirements.txt'), Object.values(externalDependencies).join('\n'));
89
+ const requirementsContent = Object.values(externalDependencies)
90
+ .map((dependency) => requirements[dependency])
91
+ .join('\n');
92
+ fs_1.default.writeFileSync(path_1.default.join(bundleDir, 'requirements.txt'), requirementsContent);
98
93
  await this.packager.packageDependencies(bundleDir);
99
94
  }
100
95
  // zip entire folder
@@ -8,11 +8,10 @@ const glob_1 = require("glob");
8
8
  const read_requirements_1 = require("../read-requirements");
9
9
  const extract_python_data_1 = require("../extract-python-data");
10
10
  const python_errors_1 = require("../python-errors");
11
- const mockPackageDescriber = (name) => ({ name, importName: name });
12
11
  describe('extractPythonData', () => {
13
12
  test('extracts python data correctly', () => {
14
13
  const rootDir = path_1.default.join(__dirname, './examples/example-1');
15
- const requirements = (0, read_requirements_1.readRequirements)(path_1.default.join(rootDir, 'requirements.txt'), mockPackageDescriber);
14
+ const requirements = (0, read_requirements_1.readRequirements)(path_1.default.join(rootDir, 'requirements.txt'));
16
15
  const steps = (0, glob_1.globSync)('**/*_step.py', { absolute: false, cwd: path_1.default.join(rootDir, 'steps') });
17
16
  for (const file of steps) {
18
17
  const result = (0, extract_python_data_1.extractPythonData)(rootDir, `/steps/${file}`, requirements);
@@ -25,17 +24,17 @@ describe('extractPythonData', () => {
25
24
  });
26
25
  test('extracts python data correctly with invalid dependency', () => {
27
26
  const rootDir = path_1.default.join(__dirname, './examples/invalid-dependency');
28
- const requirements = (0, read_requirements_1.readRequirements)(path_1.default.join(rootDir, 'requirements.txt'), mockPackageDescriber);
27
+ const requirements = (0, read_requirements_1.readRequirements)(path_1.default.join(rootDir, 'requirements.txt'));
29
28
  expect(() => (0, extract_python_data_1.extractPythonData)(rootDir, `/steps/api_step.py`, requirements)).toThrow(python_errors_1.PythonImportNotFoundError);
30
29
  });
31
30
  test('extracts python data correctly with compilation error', () => {
32
31
  const rootDir = path_1.default.join(__dirname, './examples/compilation-error');
33
- const requirements = (0, read_requirements_1.readRequirements)(path_1.default.join(rootDir, 'requirements.txt'), mockPackageDescriber);
32
+ const requirements = (0, read_requirements_1.readRequirements)(path_1.default.join(rootDir, 'requirements.txt'));
34
33
  expect(() => (0, extract_python_data_1.extractPythonData)(rootDir, `/steps/api_step.py`, requirements)).toThrow(new python_errors_1.PythonError("Compilation error: no viable alternative at input ':' at line 3:10 in /steps/api_step.py", '/steps/api_step.py'));
35
34
  });
36
35
  test('extracts python data with nested import from requirements', () => {
37
36
  const rootDir = path_1.default.join(__dirname, './examples/chessarena');
38
- const requirements = (0, read_requirements_1.readRequirements)(path_1.default.join(rootDir, 'requirements.txt'), mockPackageDescriber);
37
+ const requirements = (0, read_requirements_1.readRequirements)(path_1.default.join(rootDir, 'requirements.txt'));
39
38
  const result = (0, extract_python_data_1.extractPythonData)(rootDir, `/steps/evaluate_player_move_step.py`, requirements);
40
39
  expect(result.externalDependencies).toEqual({ chess: 'chess>=1.0.0', pydantic: 'pydantic>=2.6.1' });
41
40
  });
@@ -11,9 +11,7 @@ import requests
11
11
  from .local_module import something
12
12
  from ..parent_module import other
13
13
  `;
14
- const requirements = {
15
- requests: 'requests==2.25.1',
16
- };
14
+ const requirements = { requests: 'requests' };
17
15
  const deps = (0, get_dependencies_from_file_1.getDependenciesFromFile)(pythonCode, 'test.py', requirements);
18
16
  expect(Array.from(deps.standardLibDependencies)).toEqual(['os', 'sys', 'collections']);
19
17
  expect(Array.from(deps.externalDependencies)).toEqual(['requests']);
@@ -31,9 +29,7 @@ import json
31
29
  import numpy
32
30
  import mypackage.submodule
33
31
  `;
34
- const requirements = {
35
- numpy: 'numpy==1.21.0',
36
- };
32
+ const requirements = { numpy: 'numpy' };
37
33
  const deps = (0, get_dependencies_from_file_1.getDependenciesFromFile)(pythonCode, 'test.py', requirements);
38
34
  expect(Array.from(deps.standardLibDependencies)).toEqual(['json']);
39
35
  expect(Array.from(deps.externalDependencies)).toEqual(['numpy']);
@@ -45,9 +41,7 @@ import json
45
41
  import numpy as np
46
42
  import mypackage.submodule
47
43
  `;
48
- const requirements = {
49
- numpy: 'numpy==1.21.0',
50
- };
44
+ const requirements = { numpy: 'numpy' };
51
45
  const deps = (0, get_dependencies_from_file_1.getDependenciesFromFile)(pythonCode, 'test.py', requirements);
52
46
  expect(Array.from(deps.standardLibDependencies)).toEqual(['json']);
53
47
  expect(Array.from(deps.externalDependencies)).toEqual(['numpy']);
@@ -9,7 +9,6 @@ const path_1 = __importDefault(require("path"));
9
9
  const os_1 = require("os");
10
10
  describe('readRequirements', () => {
11
11
  let tempFilePath;
12
- const mockPackageDescriber = jest.fn((name) => ({ name, importName: name }));
13
12
  beforeEach(() => {
14
13
  // Create a temporary file path
15
14
  tempFilePath = path_1.default.join((0, os_1.tmpdir)(), `requirements-${Date.now()}.txt`);
@@ -25,7 +24,7 @@ describe('readRequirements', () => {
25
24
  numpy>=1.20.0
26
25
  flask~=2.0`;
27
26
  fs_1.default.writeFileSync(tempFilePath, content);
28
- const requirements = (0, read_requirements_1.readRequirements)(tempFilePath, mockPackageDescriber);
27
+ const requirements = (0, read_requirements_1.readRequirements)(tempFilePath);
29
28
  expect(Object.keys(requirements)).toHaveLength(3);
30
29
  expect(requirements.requests).toBe('requests==2.25.1');
31
30
  expect(requirements.numpy).toBe('numpy>=1.20.0');
@@ -40,38 +39,17 @@ numpy>=1.20.0
40
39
 
41
40
  flask~=2.0`;
42
41
  fs_1.default.writeFileSync(tempFilePath, content);
43
- const requirements = (0, read_requirements_1.readRequirements)(tempFilePath, mockPackageDescriber);
42
+ const requirements = (0, read_requirements_1.readRequirements)(tempFilePath);
44
43
  expect(Object.keys(requirements)).toHaveLength(3);
45
44
  expect(requirements.requests).toBe('requests==2.25.1');
46
45
  expect(requirements.numpy).toBe('numpy>=1.20.0');
47
46
  expect(requirements.flask).toBe('flask~=2.0');
48
47
  });
49
- test('handles complex package names and version specifiers', () => {
50
- const content = `scikit-learn==1.0.2
51
- python-dateutil==1.4
52
- Django<4.0.0,>=3.2.0`;
53
- fs_1.default.writeFileSync(tempFilePath, content);
54
- const describer = jest.fn((name) => {
55
- // mocking a describer resolution for these packages
56
- // we're going to implement it separately
57
- const map = {
58
- 'scikit-learn': 'sklearn',
59
- 'python-dateutil': 'dateutil',
60
- Django: 'django',
61
- };
62
- return map[name] ? { name, importName: map[name] } : { name, importName: name };
63
- });
64
- const requirements = (0, read_requirements_1.readRequirements)(tempFilePath, describer);
65
- expect(Object.keys(requirements)).toEqual(['sklearn', 'dateutil', 'django']);
66
- expect(requirements['sklearn']).toBe('scikit-learn==1.0.2');
67
- expect(requirements['dateutil']).toBe('python-dateutil==1.4');
68
- expect(requirements['django']).toBe('Django<4.0.0,>=3.2.0');
69
- });
70
48
  test('handles requirements with extra dependencies', () => {
71
49
  const content = `requests[security]==2.25.1
72
50
  flask[async]==2.0.1`;
73
51
  fs_1.default.writeFileSync(tempFilePath, content);
74
- const requirements = (0, read_requirements_1.readRequirements)(tempFilePath, mockPackageDescriber);
52
+ const requirements = (0, read_requirements_1.readRequirements)(tempFilePath);
75
53
  expect(Object.keys(requirements)).toHaveLength(2);
76
54
  expect(requirements['requests']).toBe('requests[security]==2.25.1');
77
55
  expect(requirements['flask']).toBe('flask[async]==2.0.1');
@@ -81,7 +59,7 @@ flask[async]==2.0.1`;
81
59
 
82
60
  # And empty lines`;
83
61
  fs_1.default.writeFileSync(tempFilePath, content);
84
- const requirements = (0, read_requirements_1.readRequirements)(tempFilePath, mockPackageDescriber);
62
+ const requirements = (0, read_requirements_1.readRequirements)(tempFilePath);
85
63
  expect(Object.keys(requirements)).toHaveLength(0);
86
64
  });
87
65
  test('handles malformed lines gracefully', () => {
@@ -90,7 +68,7 @@ flask[async]==2.0.1`;
90
68
  numpy>=1.20.0
91
69
  ==invalid-version-only`;
92
70
  fs_1.default.writeFileSync(tempFilePath, content);
93
- const requirements = (0, read_requirements_1.readRequirements)(tempFilePath, mockPackageDescriber);
71
+ const requirements = (0, read_requirements_1.readRequirements)(tempFilePath);
94
72
  expect(Object.keys(requirements)).toHaveLength(2);
95
73
  expect(requirements.requests).toBe('requests==2.25.1');
96
74
  expect(requirements.numpy).toBe('numpy>=1.20.0');
@@ -98,7 +76,7 @@ numpy>=1.20.0
98
76
  test('handles mixed line endings', () => {
99
77
  const content = 'requests==2.25.1\r\nnumpy>=1.20.0\nflask~=2.0';
100
78
  fs_1.default.writeFileSync(tempFilePath, content);
101
- const requirements = (0, read_requirements_1.readRequirements)(tempFilePath, mockPackageDescriber);
79
+ const requirements = (0, read_requirements_1.readRequirements)(tempFilePath);
102
80
  expect(Object.keys(requirements)).toHaveLength(3);
103
81
  expect(requirements.requests).toBe('requests==2.25.1');
104
82
  expect(requirements.numpy).toBe('numpy>=1.20.0');
@@ -107,7 +85,7 @@ numpy>=1.20.0
107
85
  test('handles requirements with no versions', () => {
108
86
  const content = ['requests', 'numpy', 'flask'].join('\n');
109
87
  fs_1.default.writeFileSync(tempFilePath, content);
110
- const requirements = (0, read_requirements_1.readRequirements)(tempFilePath, mockPackageDescriber);
88
+ const requirements = (0, read_requirements_1.readRequirements)(tempFilePath);
111
89
  expect(Object.keys(requirements)).toHaveLength(3);
112
90
  expect(requirements.requests).toBe('requests');
113
91
  expect(requirements.numpy).toBe('numpy');
@@ -4,26 +4,35 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const path_1 = __importDefault(require("path"));
7
- const resolve_dep_name_1 = require("../resolve-dep-name");
7
+ const resolve_dep_names_1 = require("../resolve-dep-names");
8
8
  const python_errors_1 = require("../python-errors");
9
9
  const sitePackagesDir = path_1.default.join(__dirname, 'site-packages');
10
10
  describe('resolveDepName', () => {
11
11
  test('resolves dependency names correctly', () => {
12
12
  const depNames = ['httpx'];
13
- const result = (0, resolve_dep_name_1.resolveDepNames)(depNames, sitePackagesDir);
14
- expect(result).toEqual([['httpx', 'httpx']]);
13
+ const result = (0, resolve_dep_names_1.resolveDepNames)(depNames, sitePackagesDir);
14
+ expect(result).toEqual({ httpx: 'httpx' });
15
15
  });
16
16
  test('resolves multiple dependency names correctly', () => {
17
17
  const depNames = ['httpx', 'scikit-learn', 'opencv-python'];
18
- const result = (0, resolve_dep_name_1.resolveDepNames)(depNames, sitePackagesDir);
19
- expect(result).toEqual([
20
- ['httpx', 'httpx'],
21
- ['scikit-learn', 'sklearn'],
22
- ['opencv-python', 'cv2'],
23
- ]);
18
+ const result = (0, resolve_dep_names_1.resolveDepNames)(depNames, sitePackagesDir);
19
+ expect(result).toEqual({
20
+ httpx: 'httpx',
21
+ sklearn: 'scikit-learn',
22
+ cv2: 'opencv-python',
23
+ });
24
+ });
25
+ test('resolves pymongo correctly', () => {
26
+ const depNames = ['pymongo'];
27
+ const result = (0, resolve_dep_names_1.resolveDepNames)(depNames, sitePackagesDir);
28
+ expect(result).toEqual({
29
+ pymongo: 'pymongo',
30
+ bson: 'pymongo',
31
+ gridfs: 'pymongo',
32
+ });
24
33
  });
25
34
  test('should throw an error if the dependency is not found', () => {
26
35
  const depNames = ['httpx', 'scikit-learn', 'opencv-python', 'pydantic'];
27
- expect(() => (0, resolve_dep_name_1.resolveDepNames)(depNames, sitePackagesDir)).toThrow(new python_errors_1.PythonError('Could not find dependency name in site-packages: pydantic', 'pydantic'));
36
+ expect(() => (0, resolve_dep_names_1.resolveDepNames)(depNames, sitePackagesDir)).toThrow(new python_errors_1.PythonError('Could not find dependency name in site-packages: pydantic', 'pydantic'));
28
37
  });
29
38
  });
@@ -4,4 +4,4 @@ export type PythonResult = {
4
4
  externalDependencies: Requirements;
5
5
  files: string[];
6
6
  };
7
- export declare const extractPythonData: (rootDir: string, filePath: string, externalDependencies: Requirements, fileContent?: string) => PythonResult;
7
+ export declare const extractPythonData: (rootDir: string, filePath: string, dependenciesMap: Record<string, string>, fileContent?: string) => PythonResult;
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.extractPythonData = void 0;
4
4
  const traverse_tree_1 = require("./traverse-tree");
5
- const extractPythonData = (rootDir, filePath, externalDependencies,
5
+ const extractPythonData = (rootDir, filePath, dependenciesMap,
6
6
  // optional
7
7
  fileContent) => {
8
8
  const result = {
@@ -10,10 +10,10 @@ fileContent) => {
10
10
  externalDependencies: new Set(),
11
11
  files: new Set(),
12
12
  };
13
- (0, traverse_tree_1.traverseTree)(rootDir, filePath, result, externalDependencies, fileContent);
13
+ (0, traverse_tree_1.traverseTree)(rootDir, filePath, result, dependenciesMap, fileContent);
14
14
  const resultDependencies = {};
15
15
  result.externalDependencies.forEach((dependency) => {
16
- resultDependencies[dependency] = externalDependencies[dependency];
16
+ resultDependencies[dependency] = dependenciesMap[dependency];
17
17
  });
18
18
  return {
19
19
  standardLibDependencies: Array.from(result.standardLibDependencies),
@@ -1,7 +1,6 @@
1
- import { Requirements } from './read-requirements';
2
1
  export type Dependencies = {
3
2
  standardLibDependencies: Set<string>;
4
3
  externalDependencies: Set<string>;
5
4
  projectDependencies: Set<string>;
6
5
  };
7
- export declare const getDependenciesFromFile: (content: string, path: string, requirements: Requirements) => Dependencies;
6
+ export declare const getDependenciesFromFile: (content: string, path: string, externalDependenciesMap: Record<string, string>) => Dependencies;
@@ -23,7 +23,7 @@ function parse(source, sourceName) {
23
23
  parser.addErrorListener(listener);
24
24
  return parser.file_input();
25
25
  }
26
- const getDependenciesFromFile = (content, path, requirements) => {
26
+ const getDependenciesFromFile = (content, path, externalDependenciesMap) => {
27
27
  const result = parse(content + '\n', path);
28
28
  const modulesSet = new Set();
29
29
  (0, python_ast_1.createVisitor)({
@@ -60,7 +60,7 @@ const getDependenciesFromFile = (content, path, requirements) => {
60
60
  else if (constants_1.STANDARD_LIB_MODULES.has(module)) {
61
61
  dependencies.standardLibDependencies.add(module);
62
62
  }
63
- else if (requirements[module] || requirements[moduleName]) {
63
+ else if (externalDependenciesMap[module] || externalDependenciesMap[moduleName]) {
64
64
  dependencies.externalDependencies.add(module);
65
65
  }
66
66
  else {
@@ -1,15 +1,13 @@
1
- export type Requirements = {
2
- [importName: string]: string;
3
- };
4
- type PackageInfo = {
5
- name: string;
6
- importName: string;
7
- };
8
- type PackageDescriber = (packageName: string) => PackageInfo;
1
+ /**
2
+ * { libraryName: lineFromRequirementsFile }
3
+ *
4
+ * Example:
5
+ * { scikit-learn: 'scikit-learn==1.0.2' }
6
+ */
7
+ export type Requirements = Record<string, string>;
9
8
  /**
10
9
  * Read the requirements.txt file and return a set of dependencies
11
10
  * @param filePath
12
11
  * @returns set of all dependencies names
13
12
  */
14
- export declare const readRequirements: (filePath: string, describer: PackageDescriber) => Requirements;
15
- export {};
13
+ export declare const readRequirements: (filePath: string) => Requirements;
@@ -10,7 +10,7 @@ const fs_1 = __importDefault(require("fs"));
10
10
  * @param filePath
11
11
  * @returns set of all dependencies names
12
12
  */
13
- const readRequirements = (filePath, describer) => {
13
+ const readRequirements = (filePath) => {
14
14
  const content = fs_1.default.readFileSync(filePath, 'utf8');
15
15
  const lines = content.split('\n');
16
16
  const requirements = {};
@@ -23,8 +23,8 @@ const readRequirements = (filePath, describer) => {
23
23
  // Extract package name (everything before version specifiers)
24
24
  const packageMatch = trimmedLine.match(/^([a-zA-Z0-9_-]+)/);
25
25
  if (packageMatch) {
26
- const packageInfo = describer(packageMatch[1]);
27
- requirements[packageInfo.importName] = trimmedLine;
26
+ const packageName = packageMatch[1];
27
+ requirements[packageName] = trimmedLine;
28
28
  }
29
29
  }
30
30
  return requirements;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Resolve the name of the import from the name of the package
3
3
  * @param depName the package name
4
- * @returns the import name
4
+ * @returns a map of the import name to the package name
5
5
  */
6
- export declare const resolveDepNames: (depNames: string[], sitePackagesDir: string) => [string, string][];
6
+ export declare const resolveDepNames: (depNames: string[], sitePackagesDir: string) => Record<string, string>;
@@ -10,13 +10,13 @@ const python_errors_1 = require("./python-errors");
10
10
  /**
11
11
  * Resolve the name of the import from the name of the package
12
12
  * @param depName the package name
13
- * @returns the import name
13
+ * @returns a map of the import name to the package name
14
14
  */
15
15
  const resolveDepNames = (depNames, sitePackagesDir) => {
16
16
  const folders = fs_1.default
17
17
  .readdirSync(sitePackagesDir)
18
18
  .filter((folder) => fs_1.default.statSync(path_1.default.join(sitePackagesDir, folder)).isDirectory());
19
- const result = [];
19
+ const result = {};
20
20
  for (const depName of depNames) {
21
21
  const regex = new RegExp(`^${depName.replace(/-/g, '[-_]')}-.*\\.dist-info$`);
22
22
  const folder = folders.find((folder) => regex.test(folder));
@@ -25,7 +25,7 @@ const resolveDepNames = (depNames, sitePackagesDir) => {
25
25
  const recordFile = fs_1.default.existsSync(path_1.default.join(sitePackagesDir, folder, 'RECORD'));
26
26
  if (topLevelFile) {
27
27
  const topLevel = fs_1.default.readFileSync(path_1.default.join(sitePackagesDir, folder, 'top_level.txt'), 'utf8').trim();
28
- result.push([depName, topLevel]);
28
+ result[topLevel] = depName;
29
29
  }
30
30
  else if (recordFile) {
31
31
  const record = fs_1.default.readFileSync(path_1.default.join(sitePackagesDir, folder, 'RECORD'), 'utf8').trim();
@@ -35,8 +35,7 @@ const resolveDepNames = (depNames, sitePackagesDir) => {
35
35
  // RECORD format: path/__init__.py,sha256=hash,size
36
36
  const match = /^([^/]+)\/__init__\.py,/.exec(line);
37
37
  if (match) {
38
- result.push([depName, match[1]]);
39
- break;
38
+ result[match[1]] = depName;
40
39
  }
41
40
  }
42
41
  }
@@ -1,7 +1,6 @@
1
- import { Requirements } from './read-requirements';
2
1
  export type TraverseTreeResult = {
3
2
  standardLibDependencies: Set<string>;
4
3
  externalDependencies: Set<string>;
5
4
  files: Set<string>;
6
5
  };
7
- export declare const traverseTree: (rootDir: string, filePath: string, result: TraverseTreeResult, externalDependencies: Requirements, fileContent?: string) => void;
6
+ export declare const traverseTree: (rootDir: string, filePath: string, result: TraverseTreeResult, dependenciesMap: Record<string, string>, fileContent?: string) => void;
@@ -9,7 +9,7 @@ const path_1 = __importDefault(require("path"));
9
9
  const convert_import_path_1 = require("./convert-import-path");
10
10
  const get_dependencies_from_file_1 = require("./get-dependencies-from-file");
11
11
  const python_errors_1 = require("./python-errors");
12
- const traverseTree = (rootDir, filePath, result, externalDependencies,
12
+ const traverseTree = (rootDir, filePath, result, dependenciesMap,
13
13
  // optional
14
14
  fileContent) => {
15
15
  const fileAbsolutePath = path_1.default.join(rootDir, filePath);
@@ -21,7 +21,7 @@ fileContent) => {
21
21
  result.files.add(initPath.replace(rootDir, ''));
22
22
  }
23
23
  const content = fileContent || fs_1.default.readFileSync(fileAbsolutePath, 'utf8');
24
- const dependencies = (0, get_dependencies_from_file_1.getDependenciesFromFile)(content, filePath, externalDependencies);
24
+ const dependencies = (0, get_dependencies_from_file_1.getDependenciesFromFile)(content, filePath, dependenciesMap);
25
25
  result.files.add(filePath);
26
26
  dependencies.externalDependencies.forEach((dependency) => {
27
27
  result.externalDependencies.add(dependency);
@@ -36,7 +36,7 @@ fileContent) => {
36
36
  const dependencyPath = dependencyFilePath.replace(rootDir, '');
37
37
  if (!result.files.has(dependencyPath)) {
38
38
  try {
39
- (0, exports.traverseTree)(rootDir, dependencyPath, result, externalDependencies);
39
+ (0, exports.traverseTree)(rootDir, dependencyPath, result, dependenciesMap);
40
40
  }
41
41
  catch (error) {
42
42
  if (error instanceof python_errors_1.PythonFileNotFoundError) {
@@ -44,7 +44,7 @@ fileContent) => {
44
44
  // try root folder
45
45
  try {
46
46
  const rootDependencyFilePath = path_1.default.resolve(rootDir, `${pythonPath}.py`).replace(rootDir, '');
47
- return (0, exports.traverseTree)(rootDir, rootDependencyFilePath, result, externalDependencies);
47
+ return (0, exports.traverseTree)(rootDir, rootDependencyFilePath, result, dependenciesMap);
48
48
  }
49
49
  catch (_error) {
50
50
  // let it throw
@@ -40,7 +40,7 @@ const glob_1 = require("glob");
40
40
  const generateTemplateSteps = (templateFolder) => {
41
41
  return async (rootDir, context) => {
42
42
  const templatePath = path.join(__dirname, templateFolder);
43
- const files = (0, glob_1.globSync)('**/*', { absolute: false, cwd: templatePath });
43
+ const files = (0, glob_1.globSync)('**/*', { absolute: false, cwd: templatePath, dot: true });
44
44
  try {
45
45
  for (const fileName of files) {
46
46
  const filePath = path.join(templatePath, fileName);
@@ -54,7 +54,7 @@ const generateTemplateSteps = (templateFolder) => {
54
54
  (0, fs_1.mkdirSync)(targetDir, { recursive: true });
55
55
  }
56
56
  if ((0, fs_1.statSync)(filePath).isDirectory()) {
57
- const folderPath = path.basename(filePath);
57
+ const folderPath = filePath.replace(templatePath, '');
58
58
  (0, fs_1.mkdirSync)(path.join(rootDir, folderPath), { recursive: true });
59
59
  continue;
60
60
  }
@@ -8,7 +8,7 @@ export type Generator = (rootDir: string, context: CliContext) => Promise<void>
8
8
  export const generateTemplateSteps = (templateFolder: string): Generator => {
9
9
  return async (rootDir: string, context: CliContext): Promise<void> => {
10
10
  const templatePath = path.join(__dirname, templateFolder)
11
- const files = globSync('**/*', { absolute: false, cwd: templatePath })
11
+ const files = globSync('**/*', { absolute: false, cwd: templatePath, dot: true })
12
12
 
13
13
  try {
14
14
  for (const fileName of files) {
@@ -24,7 +24,7 @@ export const generateTemplateSteps = (templateFolder: string): Generator => {
24
24
  }
25
25
 
26
26
  if (statSync(filePath).isDirectory()) {
27
- const folderPath = path.basename(filePath)
27
+ const folderPath = filePath.replace(templatePath, '')
28
28
  mkdirSync(path.join(rootDir, folderPath), { recursive: true })
29
29
  continue
30
30
  }
@@ -0,0 +1,49 @@
1
+ ---
2
+ description: How to configure database migrations in the project
3
+ globs:
4
+ alwaysApply: false
5
+ ---
6
+ # Configuring database migrations
7
+
8
+ When configuring database in the project, create a `knexfile.ts` file in the root of the project.
9
+
10
+ ```typescript
11
+ import type { Knex } from 'knex'
12
+ import * as dotenv from 'dotenv'
13
+
14
+ dotenv.config({ path: '.env' })
15
+
16
+ const config: Knex.Config = {
17
+ client: 'postgresql',
18
+ connection: {
19
+ host: process.env.DB_HOST,
20
+ port: process.env.DB_PORT,
21
+ database: process.env.DB_NAME,
22
+ user: process.env.DB_USER,
23
+ password: process.env.DB_PASS,
24
+ },
25
+ pool: {
26
+ min: 2,
27
+ max: 10,
28
+ },
29
+ migrations: {
30
+ tableName: 'knex_migrations',
31
+ },
32
+ }
33
+
34
+ export default config
35
+ ```
36
+
37
+ ## Creating a new migration
38
+
39
+ Prefix should be timestamp in milliseconds.
40
+
41
+ ```bash
42
+ npm run migrate:make 1727115600000_create_users_table
43
+ ```
44
+
45
+ ## Running migrations
46
+
47
+ ```bash
48
+ npm run migrate:latest
49
+ ```
@@ -0,0 +1,83 @@
1
+ ---
2
+ description: Database connections and queries
3
+ globs: src/repositories/**/*.ts
4
+ alwaysApply: false
5
+ ---
6
+ # Database Guide
7
+
8
+ - Prefer knex to interact with the database
9
+ - http://npmjs.com/package/knex
10
+ - Use knex migrations to manage database schema changes
11
+ - Do NOT create DB calls directly in steps or services, ALWAYS create a repository file to handle the database calls. Follow DDD principles.
12
+
13
+ ## Add commands to package.json
14
+
15
+ ```json
16
+ {
17
+ "scripts": {
18
+ "migrate:up": "knex migrate:latest",
19
+ "migrate:down": "knex migrate:rollback",
20
+ }
21
+ }
22
+ ```
23
+
24
+ ## Creating base database connection
25
+
26
+ - When SQL database is used, create a database connection file in the `src/repositories/database.ts` file.
27
+ - All columns in code are cammelCase, however, in the database and in the migration, we use snake_case.
28
+ - Avoid numeric incremental IDs, use UUIDs instead. Make sure to add foreign key with cascade delete when applicable.
29
+
30
+ ```typescript
31
+ import knex, { Knex } from 'knex'
32
+ /**
33
+ * Create these functions to convert between camelCase and snake_case.
34
+ * This is important to keep the consistency of the data.
35
+ */
36
+ import { camelToSnake, snakeToCamelObject } from '../utils/case-conversion'
37
+
38
+ const isProduction = process.env.NODE_ENV === 'production'
39
+ const isDevelopment = process.env.NODE_ENV === 'development'
40
+
41
+ // Knex configuration
42
+ const knexConfig: Knex.Config = {
43
+ client: 'pg',
44
+ connection: {
45
+ host: process.env.DB_HOST,
46
+ port: process.env.DB_PORT,
47
+ user: process.env.DB_USER,
48
+ password: process.env.DB_PASSWORD,
49
+ database: process.env.DB_NAME,
50
+ ssl: process.env.DB_SSL ? {
51
+ /** In development, we might use self-signed certs */
52
+ rejectUnauthorized: isProduction,
53
+ /** Add CA certificate if needed */
54
+ ca: undefined,
55
+ } : false,
56
+ },
57
+ pool: {
58
+ min: 2,
59
+ max: 10,
60
+ idleTimeoutMillis: 30000,
61
+ },
62
+ debug: isDevelopment,
63
+ wrapIdentifier: (value, origImpl) => origImpl(camelToSnake(value)),
64
+ postProcessResponse: result =>
65
+ Array.isArray(result)
66
+ ? result.map(row => snakeToCamelObject(row))
67
+ : snakeToCamelObject(result),
68
+ }
69
+
70
+ // Create a singleton instance
71
+ let db: Knex | null = null
72
+
73
+ /**
74
+ * Get the database instance
75
+ * @returns Knex instance
76
+ */
77
+ export const getDb = (): Knex => {
78
+ if (!db) {
79
+ db = knex(knexConfig)
80
+ }
81
+ return db
82
+ }
83
+ ```