@izara_project/izara-core-generate-service-code 1.0.64 → 1.0.66

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 (256) hide show
  1. package/README.md +73 -11
  2. package/index.js +0 -5
  3. package/package.json +7 -6
  4. package/src/compile/compileProject.js +26 -0
  5. package/src/compile/loadSchemas.js +28 -0
  6. package/src/emit/crud/dynamicCrudFlowSchemaTemplate.js +11 -0
  7. package/src/emit/crud/emitCrudApplicationArtifacts.js +157 -0
  8. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +84 -0
  9. package/src/emit/crud/generateCrudApplicationArtifacts.js +16 -0
  10. package/src/emit/crud/generateDynamicCrudFlowSchemas.js +21 -0
  11. package/src/emit/crud/loadLocalSchemaArrays.js +8 -0
  12. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowObjects/templates/crud → emit/crud/templates}/CreateEndpoint_Main.ejs +1 -1
  13. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowObjects/templates/crud → emit/crud/templates}/DeleteEndpoint_Main.ejs +1 -1
  14. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowObjects/templates/step → emit/crud/templates}/FlowEndpointBeforeLogical_Main.ejs +2 -2
  15. package/src/emit/crud/templates/FlowEndpointComplete_Main.ejs +75 -0
  16. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/endpoint → emit/crud/templates}/FlowEndpoint_HdrWbs.ejs +1 -1
  17. package/src/{codeGenerators/app/src/generatedCode/ProcessLogical/templates/ProcessLogical_HdrSqs.ejs → emit/crud/templates/FlowHandler_HdrSqs.ejs} +52 -56
  18. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/endpoint → emit/crud/templates}/FlowMain_Wbs.ejs +1 -3
  19. package/src/emit/crud/templates/GetRangeEndpoint_Main.ejs +127 -0
  20. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowObjects/templates/crud → emit/crud/templates}/UpdateEndpoint_Main.ejs +1 -1
  21. package/src/emit/custom/customFlows.js +70 -0
  22. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +308 -0
  23. package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +22 -0
  24. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/endpoint → emit/custom/templates}/FlowEndpoint_Main.ejs +1 -1
  25. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/step → emit/custom/templates}/FlowStep_Main.ejs +1 -1
  26. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas → emit/custom}/templates/s3/ConfirmReserved_Main.ejs +5 -5
  27. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas → emit/custom}/templates/s3/CreateObject_HdrWbs.ejs +1 -1
  28. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas → emit/custom}/templates/s3/CreateObject_Main.ejs +3 -3
  29. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas → emit/custom}/templates/s3/CreatePreSignUrl_Main.ejs +4 -5
  30. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas → emit/custom}/templates/s3/FlowHandler_HdrS3.ejs +2 -8
  31. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas → emit/custom}/templates/s3/ProcessS3File_Main.ejs +1 -1
  32. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas → emit/custom}/templates/s3/ReservedLimit_Main.ejs +5 -6
  33. package/src/emit/custom/templates/triggerCache/CheckTriggerCache_HdrSqs.ejs +32 -0
  34. package/src/emit/custom/templates/triggerCache/CheckTriggerCache_Main.ejs +63 -0
  35. package/src/emit/custom/templates/triggerCache/TriggerCacheComplete_Main.ejs +35 -0
  36. package/src/emit/custom/templates/triggerCache/TriggerCache_Main.ejs +16 -0
  37. package/src/emit/function/functionYamlArtifact.js +111 -0
  38. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +117 -0
  39. package/src/emit/rbac/emitRbacApplicationArtifacts.js +256 -0
  40. package/src/emit/rbac/generateCreateTargetRoleHandler.js +19 -0
  41. package/src/emit/rbac/generateDynamicRbacFlowSchemas.js +21 -0
  42. package/src/emit/rbac/rbacFlowTag.js +7 -0
  43. package/src/emit/rbac/templates/CreateTargetRole_HdrSqs.ejs +24 -0
  44. package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +25 -0
  45. package/src/emit/rbac/templates/DynamicRbacFlowSchema.ejs +5 -0
  46. package/src/emit/rbac/templates/ListRbac_HdrApi.ejs +17 -0
  47. package/src/emit/rbac/templates/ListRbac_HdrSqs.ejs +13 -0
  48. package/src/emit/rbac/templates/ListRbac_Main.ejs +29 -0
  49. package/src/emit/rbac/templates/RbacMutation_Main.ejs +22 -0
  50. package/src/emit/rbac/templates/UserRbacFlow_HdrInv.ejs +10 -0
  51. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +44 -0
  52. package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +33 -0
  53. package/src/emit/relationship/dynamicRelationshipFlowSchemaTemplate.js +11 -0
  54. package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +66 -0
  55. package/src/emit/relationship/emitRelationshipApplicationArtifacts.js +147 -0
  56. package/src/emit/relationship/generateDynamicRelationshipFlowSchemas.js +23 -0
  57. package/src/emit/relationship/generateRelationshipApplicationArtifacts.js +22 -0
  58. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowRelationships/templates/relationship/ProcessChangeRelationshipComplete_Main.ejs → emit/relationship/templates/ChangeRelationshipComplete_Main.ejs} +1 -1
  59. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowRelationships/templates/relationship/ProcessChangeRelationship_Main.ejs → emit/relationship/templates/ChangeRelationship_Main.ejs} +10 -2
  60. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowRelationships/templates/relationship/ProcessCreateRelationshipComplete_Main.ejs → emit/relationship/templates/CreateRelationshipComplete_Main.ejs} +1 -1
  61. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowRelationships/templates/relationship/ProcessCreateRelationship_Main.ejs → emit/relationship/templates/CreateRelationship_Main.ejs} +1 -1
  62. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowRelationships/templates/relationship/ProcessDeleteRelationshipComplete_Main.ejs → emit/relationship/templates/DeleteRelationshipComplete_Main.ejs} +1 -1
  63. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowRelationships/templates/relationship/ProcessDeleteRelationship_Main.ejs → emit/relationship/templates/DeleteRelationship_Main.ejs} +1 -1
  64. package/src/emit/relationship/templates/FlowHandler_HdrApi.ejs +51 -0
  65. package/src/{codeGenerators/app/src/generatedCode/Flow/_shared/handlers → emit/relationship/templates}/FlowHandler_HdrDsq.ejs +1 -1
  66. package/src/emit/relationship/templates/FlowHandler_HdrInv.ejs +45 -0
  67. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowRelationships/templates/relationship/ProcessGetRelationshipComplete_Main.ejs → emit/relationship/templates/GetRelationshipComplete_Main.ejs} +1 -1
  68. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowRelationships/templates/relationship/ProcessGetRelationship_Main.ejs → emit/relationship/templates/GetRelationship_Main.ejs} +1 -1
  69. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowRelationships/templates/relationship/ProcessMoveRelationship_Main.ejs → emit/relationship/templates/MoveRelationship_Main.ejs} +9 -1
  70. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowRelationships/templates/relationship/ProcessUpdateRelationshipComplete_Main.ejs → emit/relationship/templates/UpdateRelationshipComplete_Main.ejs} +1 -1
  71. package/src/{codeGenerators/app/src/generatedCode/Flow/FlowRelationships/templates/relationship/ProcessUpdateRelationship_Main.ejs → emit/relationship/templates/UpdateRelationship_Main.ejs} +1 -1
  72. package/src/emit/resource/emitResourceArtifacts.js +300 -0
  73. package/src/emit/resource/generateResourceArtifacts.js +20 -0
  74. package/src/{codeGenerators/resource/sls_yaml/templates/crud → emit/resource/templates}/ResourceBeforeLogicalYaml.ejs +1 -1
  75. package/src/{codeGenerators/resource/sls_yaml/templates/crud → emit/resource/templates}/ResourceSqsYaml.ejs +6 -6
  76. package/src/{codeGenerators/app/sls_yaml → emit/resource}/templates/SharedResource_Yaml.ejs +8 -8
  77. package/src/emit/system/emitSystemWebSocketArtifacts.js +182 -0
  78. package/src/generate.js +60 -126
  79. package/src/output/commitArtifacts.js +213 -0
  80. package/src/output/mergeHooks.js +55 -0
  81. package/src/output/validateArtifacts.js +62 -0
  82. package/src/plan/buildGenerationPlan.js +50 -0
  83. package/test/core.test.js +159 -0
  84. package/test/createTargetRoleHandler.test.js +68 -0
  85. package/test/crudApplicationArtifacts.test.js +107 -0
  86. package/test/customFlowApplicationArtifacts.test.js +294 -0
  87. package/test/dynamicCrudFlowSchemas.test.js +136 -0
  88. package/test/dynamicRbacFlowSchemas.test.js +101 -0
  89. package/test/dynamicRelationshipFlowSchemas.test.js +99 -0
  90. package/test/functionYamlArtifact.test.js +34 -0
  91. package/test/intTestApi.test.js +29 -0
  92. package/test/publicApi.test.js +209 -0
  93. package/test/relationshipApplicationArtifacts.test.js +68 -0
  94. package/test/resourceArtifacts.test.js +121 -0
  95. package/jsconfig.json +0 -9
  96. package/src/__tests__/getIntTestConfig.test.js +0 -51
  97. package/src/__tests__/intTestGeneratorShared.test.cjs +0 -169
  98. package/src/__tests__/pathIntTest.test.js +0 -103
  99. package/src/codeGenerators/app/initial_setup/InitialSetupGenerator.js +0 -199
  100. package/src/codeGenerators/app/initial_setup/templates/InitialSetup_LambdaRole.ejs +0 -50
  101. package/src/codeGenerators/app/initial_setup/templates/InitialSetup_SnsService.ejs +0 -15
  102. package/src/codeGenerators/app/initial_setup/templates/InitialSetup_TableName.ejs +0 -9
  103. package/src/codeGenerators/app/sls_yaml/FindDataYamlGenerator.js +0 -23
  104. package/src/codeGenerators/app/sls_yaml/FunctionYamlGenerator.js +0 -322
  105. package/src/codeGenerators/app/sls_yaml/ProcessLogicalYamlGenerator.js +0 -21
  106. package/src/codeGenerators/app/sls_yaml/RoleNameConfigGenerator.js +0 -48
  107. package/src/codeGenerators/app/sls_yaml/SharedResourceYamlGenerator.js +0 -504
  108. package/src/codeGenerators/app/sls_yaml/__tests__/SharedResourceYamlGenerator.test.js +0 -235
  109. package/src/codeGenerators/app/sls_yaml/_policy/PolicyEmitter.js +0 -46
  110. package/src/codeGenerators/app/sls_yaml/_policy/PolicyRegistry.js +0 -94
  111. package/src/codeGenerators/app/sls_yaml/_policy/__tests__/PolicyEmitter.test.js +0 -55
  112. package/src/codeGenerators/app/sls_yaml/_policy/__tests__/PolicyRegistry.test.js +0 -48
  113. package/src/codeGenerators/app/sls_yaml/_policy/templates/ManagedPolicy_Yaml.ejs +0 -22
  114. package/src/codeGenerators/app/sls_yaml/renderYamlTemplate.js +0 -13
  115. package/src/codeGenerators/app/sls_yaml/templates/FindData_Yaml.ejs +0 -10
  116. package/src/codeGenerators/app/sls_yaml/templates/FunctionYaml_Api.ejs +0 -21
  117. package/src/codeGenerators/app/sls_yaml/templates/FunctionYaml_EventBridge.ejs +0 -14
  118. package/src/codeGenerators/app/sls_yaml/templates/FunctionYaml_Inv.ejs +0 -6
  119. package/src/codeGenerators/app/sls_yaml/templates/FunctionYaml_Sqs.ejs +0 -11
  120. package/src/codeGenerators/app/sls_yaml/templates/FunctionYaml_Wbs.ejs +0 -11
  121. package/src/codeGenerators/app/sls_yaml/templates/ProcessLogical_Yaml.ejs +0 -32
  122. package/src/codeGenerators/app/sls_yaml/templates/RoleNameConfig_Yaml.ejs +0 -5
  123. package/src/codeGenerators/app/src/generatedCode/FindData/FindDataGenerator.js +0 -238
  124. package/src/codeGenerators/app/src/generatedCode/FindData/templates/FindData_HdrSqs.ejs +0 -87
  125. package/src/codeGenerators/app/src/generatedCode/FindData/templates/FindData_Main.ejs +0 -108
  126. package/src/codeGenerators/app/src/generatedCode/FindData/templates/GetByStorage/getByDynamo.ejs +0 -32
  127. package/src/codeGenerators/app/src/generatedCode/FindData/templates/GetByStorage/getByGraph.ejs +0 -87
  128. package/src/codeGenerators/app/src/generatedCode/Flow/FlowObjects/.gitkeep +0 -0
  129. package/src/codeGenerators/app/src/generatedCode/Flow/FlowObjects/EndpointsGenerator.js +0 -120
  130. package/src/codeGenerators/app/src/generatedCode/Flow/FlowObjects/templates/step/FlowEndpointComplete_Main.ejs +0 -313
  131. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/RbacFlowGenerator.js +0 -116
  132. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/templates/rbac/CreateRolePermissions.ejs +0 -135
  133. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/templates/rbac/CreateTargetRole.ejs +0 -131
  134. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/templates/rbac/CreateUserRole.ejs +0 -150
  135. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/templates/rbac/DeleteRolePermissions.ejs +0 -132
  136. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/templates/rbac/DeleteTargetRole.ejs +0 -132
  137. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/templates/rbac/DeleteUserFromRole.ejs +0 -150
  138. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/templates/rbac/FlowRbac_Main.ejs +0 -252
  139. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/templates/rbac/ListRolePermissions.ejs +0 -120
  140. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/templates/rbac/ListTargetRole.ejs +0 -122
  141. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/templates/rbac/ListUserInRoles.ejs +0 -117
  142. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRelationships/RelationshipFlowGenerator.js +0 -148
  143. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/.gitkeep +0 -0
  144. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/StatusFieldGenerator.js +0 -109
  145. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/WebSocketGenerator.js +0 -122
  146. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/endpoint/FlowEntryPoint_Main.ejs +0 -38
  147. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/statusField/CompleteStatusFieldSns_Yaml.ejs +0 -52
  148. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/statusField/CompleteStatusField_HdrSqs.ejs +0 -84
  149. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/statusField/CompleteStatusField_Main.ejs +0 -78
  150. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/step/plugIns/FlowStep_ByConfig_Awaiting_Main.ejs +0 -123
  151. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/step/plugIns/FlowStep_ByConfig_Paginated_Main.ejs +0 -59
  152. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/step/plugIns/FlowStep_PlugIn_Main.ejs +0 -72
  153. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/step/plugIns/FlowStep_RecievePlugIn_Main.ejs +0 -76
  154. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/step/plugIns/templateAwaitingStep.ejs +0 -41
  155. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/step/plugIns/templateSendPlugin.ejs +0 -18
  156. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/webSocket/ProcessWebSocketFlow_Yaml.ejs +0 -26
  157. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/webSocket/ProcessWebSocketSub_Yaml.ejs +0 -7
  158. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/webSocket/ProcessWebSocket_HdrSqs.ejs +0 -66
  159. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/webSocket/ProcessWebSocket_Main.ejs +0 -115
  160. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/webSocket/ProcessWebSocket_Yaml.ejs +0 -36
  161. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/webSocket/WebSocketConnect_Main.ejs +0 -52
  162. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/webSocket/WebSocketConnect_Yaml.ejs +0 -13
  163. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/webSocket/WebSocketDynamoDb_Yaml.ejs +0 -28
  164. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/BaseDsqHandler.js +0 -55
  165. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/BaseSqsHandler.js +0 -66
  166. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/__tests__/BaseDsqHandler.test.js +0 -93
  167. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/dsq.js +0 -5
  168. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/eventBridge.js +0 -25
  169. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/extTopic.js +0 -6
  170. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/lambdaSyncApi.js +0 -43
  171. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/lambdaSyncInv.js +0 -43
  172. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/ownTopic.js +0 -54
  173. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/registry.js +0 -17
  174. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/s3.js +0 -56
  175. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/s3Components/ConfirmAfterUploadS3Generator.js +0 -46
  176. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/s3Components/CreateObjectGenerator.js +0 -50
  177. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/s3Components/CreatePreSignUrlGenerator.js +0 -48
  178. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/s3Components/ProcessAfterUploadS3Generator.js +0 -49
  179. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/s3Components/ReservedLimitGenerator.js +0 -47
  180. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/eventTypes.js +0 -23
  181. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowClassifier.js +0 -50
  182. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowEntryPointBase.js +0 -106
  183. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowMainFunctionBase.js +0 -172
  184. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowNaming.js +0 -37
  185. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowSelection.js +0 -19
  186. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowStepBase.js +0 -235
  187. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowStepNormalizer.js +0 -75
  188. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowValidator.js +0 -236
  189. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/propertyNormalizer.js +0 -15
  190. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/registry.js +0 -7
  191. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/roleNameDetection.js +0 -49
  192. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/triggerCacheBase.js +0 -177
  193. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/triggerCache/CheckTriggerCache_HdrSqs.ejs +0 -89
  194. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/triggerCache/CheckTriggerCache_Main.ejs +0 -83
  195. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/triggerCache/ProcessTriggerCache_HdrSqs.ejs +0 -103
  196. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/triggerCache/ProcessTriggerCache_Main.ejs +0 -58
  197. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/triggerCache/TriggerCacheComplete_HdrDsq.ejs +0 -104
  198. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/triggerCache/TriggerCacheComplete_HdrSqs.ejs +0 -88
  199. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/triggerCache/TriggerCacheComplete_Main.ejs +0 -80
  200. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/triggerCache/TriggerCacheQueue_Yaml.ejs +0 -36
  201. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/yaml/SharedFunctionSqs_Yaml.ejs +0 -13
  202. package/src/codeGenerators/app/src/generatedCode/ProcessLogical/ProcessLogicalGenerator.js +0 -29
  203. package/src/codeGenerators/app/src/generatedCode/ProcessLogical/templates/PaginateProcessLogical_HdrDsq.ejs +0 -177
  204. package/src/codeGenerators/app/src/generatedCode/ProcessLogical/templates/PaginateProcessLogical_HdrSqs.ejs +0 -155
  205. package/src/codeGenerators/app/src/generatedCode/ProcessLogical/templates/PaginateProcessLogical_Main.ejs +0 -268
  206. package/src/codeGenerators/app/src/generatedCode/ProcessLogical/templates/ProcessLogical_Main.ejs +0 -450
  207. package/src/codeGenerators/app/src/generatedCode/SystemFlowSchemas/RegisterGenerator.js +0 -149
  208. package/src/codeGenerators/app/src/generatedCode/SystemFlowSchemas/templates/register/RegisterComplete_HdrSqs.ejs +0 -85
  209. package/src/codeGenerators/app/src/generatedCode/SystemFlowSchemas/templates/register/RegisterComplete_Main.ejs +0 -176
  210. package/src/codeGenerators/app/src/generatedCode/SystemFlowSchemas/templates/register/Register_HdrWbs.ejs +0 -80
  211. package/src/codeGenerators/app/src/generatedCode/SystemFlowSchemas/templates/register/Register_Main.ejs +0 -164
  212. package/src/codeGenerators/app/src/generatedCode/libs/ConstsGenerator.js +0 -28
  213. package/src/codeGenerators/app/src/generatedCode/libs/GenerateCodeLibsGenerator.js +0 -28
  214. package/src/codeGenerators/app/src/generatedCode/libs/templates/Consts.ejs +0 -448
  215. package/src/codeGenerators/app/src/generatedCode/libs/templates/GenerateCodeLibs.ejs +0 -124
  216. package/src/codeGenerators/resource/sls_yaml/DynamoDBGenerator.js +0 -87
  217. package/src/codeGenerators/resource/sls_yaml/FlowOutGenerator.js +0 -70
  218. package/src/codeGenerators/resource/sls_yaml/FlowResourceYamlGenerator.js +0 -182
  219. package/src/core/renderTemplateFile.js +0 -22
  220. package/src/core/validate.js +0 -165
  221. package/src/generateCode.js +0 -358
  222. package/src/generateSchema.js +0 -123
  223. package/src/parsers/flowSchemaParser.js +0 -112
  224. package/src/parsers/objectSchemaParser.js +0 -39
  225. package/src/parsers/relationshipSchemaParser.js +0 -51
  226. package/src/schemaGenerators/app/src/schemas/FlowSchemas/FlowSchemaGenerator.js +0 -107
  227. package/src/schemaGenerators/app/src/schemas/FlowSchemas/RbacFlowSchemaGenerator.js +0 -98
  228. package/src/schemaGenerators/app/src/schemas/FlowSchemas/RelationshipFlowSchemaGenerator.js +0 -89
  229. package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/DynamicFlowSchemaTemplate.ejs +0 -41
  230. package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/DynamicRbacFlowSchemaTemplate.ejs +0 -20
  231. package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/RelationshipFlowSchemaTemplate.ejs +0 -33
  232. package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/UserRbacFlowSchemaTemplate.ejs +0 -22
  233. package/src/schemaGenerators/app/src/schemas/ObjectSchemas/AttributeTreeSchemaGenerator.js +0 -124
  234. package/src/schemaGenerators/app/src/schemas/ObjectSchemas/PropertyValueSchemaGenerator.js +0 -119
  235. package/src/schemaGenerators/app/src/schemas/ObjectSchemas/templates/DynamicAttributeTreeManagerSchemaTemplate.ejs +0 -14
  236. package/src/schemaGenerators/app/src/schemas/ObjectSchemas/templates/DynamicAttributeTreeStandardSchemaTemplate.ejs +0 -13
  237. package/src/schemaGenerators/app/src/schemas/ObjectSchemas/templates/DynamicPropertyValueSchemaTemplate.ejs +0 -15
  238. package/src/schemaGenerators/app/src/schemas/RelationshipSchemas/AttributeTreeRelationshipSchemaGenerator.js +0 -149
  239. package/src/schemaGenerators/app/src/schemas/RelationshipSchemas/PropertyValueRelationshipSchemaGenerator.js +0 -143
  240. package/src/schemaGenerators/app/src/schemas/RelationshipSchemas/templates/DynamicAttributeTreeRelationshipSchemaTemplate.ejs +0 -7
  241. package/src/schemaGenerators/app/src/schemas/RelationshipSchemas/templates/DynamicPropertyValueRelationshipSchemaTemplate.ejs +0 -7
  242. package/src/schemaGenerators/app/src/schemas/SystemTextSchemas/SystemTextGenerator.js +0 -102
  243. package/src/schemaGenerators/app/src/schemas/SystemTextSchemas/templates/SystemText_Template.ejs +0 -10
  244. package/test_schema.js +0 -2
  245. /package/src/{codeGenerators/app/src/generatedCode/Flow/_shared/handlers → emit/crud/templates}/FlowHandler_HdrApi.ejs +0 -0
  246. /package/src/{codeGenerators/app/src/generatedCode/Flow/_shared/handlers → emit/crud/templates}/FlowHandler_HdrInv.ejs +0 -0
  247. /package/src/{codeGenerators/app/src/generatedCode/Flow/FlowObjects/templates/crud → emit/crud/templates}/GetEndpoint_Main.ejs +0 -0
  248. /package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas → emit/custom}/templates/s3/ConfirmReserved_HdrSqs.ejs +0 -0
  249. /package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas → emit/custom}/templates/s3/CreatePreSignUrl_HdrSqs.ejs +0 -0
  250. /package/src/{codeGenerators/app/src/generatedCode/Flow/FlowSchemas → emit/custom}/templates/s3/ReservedLimit_HdrSqs.ejs +0 -0
  251. /package/src/{codeGenerators/app/src/generatedCode/Flow/_shared/handlers → emit/relationship/templates}/FlowHandler_HdrSqs.ejs +0 -0
  252. /package/src/{codeGenerators/app/src/generatedCode/Flow/FlowRelationships/templates/relationship/ProcessMoveRelationshipComplete_Main.ejs → emit/relationship/templates/MoveRelationshipComplete_Main.ejs} +0 -0
  253. /package/src/{codeGenerators/resource/sls_yaml → emit/resource}/templates/DynamoDBTable_Yaml.ejs +0 -0
  254. /package/src/{codeGenerators/resource/sls_yaml → emit/resource}/templates/FlowOut_Yaml.ejs +0 -0
  255. /package/src/{codeGenerators/resource/sls_yaml/templates/crud → emit/resource/templates}/ResourceYaml.ejs +0 -0
  256. /package/src/{codeGenerators/resource/sls_yaml → emit/resource}/templates/SystemDynamoDB_Yaml.ejs +0 -0
package/src/generate.js CHANGED
@@ -1,130 +1,64 @@
1
- /*
2
- Copyright (C) 2020 Sven Mason <http://izara.io>
3
-
4
- This program is free software: you can redistribute it and/or modify
5
- it under the terms of the GNU Affero General Public License as published by
6
- the Free Software Foundation, either version 3 of the License, or
7
- (at your option) any later version.
8
-
9
- This program is distributed in the hope that it will be useful,
10
- but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- GNU Affero General Public License for more details.
13
-
14
- You should have received a copy of the GNU Affero General Public License
15
- along with this program. If not, see <http://www.gnu.org/licenses/>.
16
- */
17
-
18
- import { join } from 'path';
19
- import { validator } from '@izara_project/izara-core-library-service-schemas';
20
- import { basicValidatorSchema } from '@izara_project/izara-shared-service-schemas';
21
- import { generateCode } from './generateCode.js';
22
- import { generateSchema } from './generateSchema.js';
23
-
24
- const { validateLocalSchema } = validator;
25
-
26
- /**
27
- * High-level API to validate schemas and generate code.
28
- * Wires legacy Logger and validateLocalSchema.
29
- *
30
- * @param {string} rootPath - The root path of the project.
31
- * @param {object} [options={}] - Configuration options.
32
- * @param {object} [options.logger] - Logger instance.
33
- * @param {string} [options.configPath] - Path to the serverless configuration file.
34
- * @param {string} [options.outputPath] - Output directory path.
35
- * @param {boolean} [options.skipValidation=false] - Whether to skip schema validation.
36
- * @param {boolean} [options.skipGenerateSchema=false] - Whether to skip schema generation.
37
- * @param {boolean} [options.skipGenerateCode=false] - Whether to skip code generation.
38
- * @param {Array} [options.schemaTemplateConfig] - Schema template configuration.
39
- * @returns {Promise<{durationMs: number}>} Generation duration details.
40
- */
41
- async function generate(rootPath, options = {}) {
42
- const {
43
- logger = createSilentLogger(),
44
- configPath = join(rootPath, 'config', 'serverless.config.yml'),
45
- outputPath = rootPath,
46
- skipValidation = false,
47
- skipGenerateSchema = false,
48
- skipGenerateCode = false,
49
- schemaTemplateConfig
50
- } = options;
51
-
52
- const schemasPath = join(rootPath, 'app', 'src', 'schemas');
53
-
54
- if (!skipGenerateSchema) {
55
- await generateSchema(rootPath, {
56
- configPath,
57
- outputPath,
58
- schemaTemplateConfig
59
- });
60
- }
61
-
62
- if (!skipValidation) {
63
- patchFlowStepsValidationSchema();
64
-
65
- console.info('[INFO] [generate] STATUS=VALIDATING | local schemas...');
66
- const validateStartTime = Date.now();
67
- const result = await validateLocalSchema({ logger }, schemasPath, configPath);
68
- const validateDuration = Date.now() - validateStartTime;
69
-
70
- console.info(
71
- `[INFO] [generate] STATUS=VALIDATED | errors=${result.validateErrors.length} | elapsedMs=${validateDuration}`
72
- );
73
-
74
- if (result.validateErrors.length > 0) {
75
- logger.error(
76
- 'Validation failed with following errors:',
77
- result.validateErrors
78
- );
79
- const err = new Error('Schema validation failed');
80
- err.validateErrors = result.validateErrors;
81
- throw err;
82
- }
83
- }
84
-
85
- if (skipGenerateCode) {
86
- return { durationMs: 0 };
1
+ import { buildGenerationPlan } from './plan/buildGenerationPlan.js';
2
+ import { commitArtifacts } from './output/commitArtifacts.js';
3
+ import { compileProject } from './compile/compileProject.js';
4
+ import { crudApplicationManagedPaths, emitCrudApplicationArtifacts } from './emit/crud/emitCrudApplicationArtifacts.js';
5
+ import { dynamicCrudFlowSchemaPaths, emitDynamicCrudFlowSchemas } from './emit/crud/emitDynamicCrudFlowSchemas.js';
6
+ import { customFlowApplicationManagedPaths, emitCustomFlowApplicationArtifacts } from './emit/custom/emitCustomFlowApplicationArtifacts.js';
7
+ import { emitDynamicRbacFlowSchemas, rbacFlowSchemaManagedPaths } from './emit/rbac/emitDynamicRbacFlowSchemas.js';
8
+ import { emitRbacApplicationArtifacts, rbacApplicationManagedPaths } from './emit/rbac/emitRbacApplicationArtifacts.js';
9
+ import { dynamicRelationshipFlowSchemaPaths, emitDynamicRelationshipFlowSchemas } from './emit/relationship/emitDynamicRelationshipFlowSchemas.js';
10
+ import { emitRelationshipApplicationArtifacts, relationshipApplicationManagedPaths } from './emit/relationship/emitRelationshipApplicationArtifacts.js';
11
+ import { emitResourceArtifacts, resourceArtifactPaths } from './emit/resource/emitResourceArtifacts.js';
12
+ import { loadLocalSchemaDirectory } from './compile/loadSchemas.js';
13
+ import { emitSystemWebSocketArtifacts, hasSystemWebSocket, systemWebSocketManagedPaths } from './emit/system/emitSystemWebSocketArtifacts.js';
14
+
15
+ export async function generate(rootPath, options = {}) {
16
+ const startedAt = Date.now();
17
+ const logger = options.logger;
18
+ logger?.info?.(`[INFO] [Generate] STATUS=STARTED | rootPath=${rootPath}`);
19
+ try {
20
+ const project = compileProject({ ...options, rootPath });
21
+ const [objects, relationships, flows] = await Promise.all([
22
+ loadLocalSchemaDirectory(project, 'ObjectSchemas'),
23
+ loadLocalSchemaDirectory(project, 'RelationshipSchemas'),
24
+ loadLocalSchemaDirectory(project, 'FlowSchemas')
25
+ ]);
26
+ logger?.debug?.(`[DEBUG] [Generate] STATUS=SCHEMAS_LOADED | objects=${objects.length} relationships=${relationships.length} flows=${flows.length}`);
27
+ const groups = await emitGroups({ project, objects, relationships, flows });
28
+ logger?.debug?.(`[DEBUG] [Generate] STATUS=ARTIFACTS_EMITTED | ${groups.map(group => `${group.scope}=${group.artifacts.length}`).join(' ')}`);
29
+ const files = groups.length === 0
30
+ ? []
31
+ : await commitArtifacts(buildGenerationPlan(project, groups.flatMap(group => group.artifacts), {
32
+ managedScopes: Object.fromEntries(groups.map(group => [group.scope, group.managedPaths]))
33
+ }));
34
+ const durationMs = Date.now() - startedAt;
35
+ logger?.info?.(`[INFO] [Generate] STATUS=FINISHED | files=${files.length} durationMs=${durationMs}`);
36
+
37
+ return { project, durationMs, files };
38
+ } catch (error) {
39
+ logger?.error?.(`[ERROR] [Generate] STATUS=FAILED | durationMs=${Date.now() - startedAt}`, error);
40
+ throw error;
87
41
  }
88
-
89
- const startTime = Date.now();
90
- await generateCode(rootPath, { outputPath, configPath });
91
- return { durationMs: Date.now() - startTime };
92
42
  }
93
43
 
94
- function patchFlowStepsValidationSchema() {
95
- const flowStepsSchema = basicValidatorSchema.basicFlowSchema?.properties?.flowSteps;
96
- if (!flowStepsSchema || flowStepsSchema.oneOf || !flowStepsSchema.items) {
97
- return;
98
- }
99
-
100
- const objectStepSchema = {
101
- ...flowStepsSchema.items,
102
- required: (flowStepsSchema.items.required || []).filter(
103
- item => item !== 'stepName'
104
- )
105
- };
106
-
107
- basicValidatorSchema.basicFlowSchema.properties.flowSteps = {
108
- oneOf: [
109
- flowStepsSchema,
110
- {
111
- type: 'object',
112
- minProperties: 1,
113
- patternProperties: {
114
- [basicValidatorSchema.strNotEmptyRegex]: objectStepSchema
115
- }
116
- }
117
- ]
118
- };
44
+ async function emitGroups({ project, objects, relationships, flows }) {
45
+ const [crud, relationship, rbac, system, resource] = await Promise.all([
46
+ emitCrudApplicationArtifacts({ objects, flows, serviceTag: project.serviceTag }),
47
+ emitRelationshipApplicationArtifacts({ relationships, flows, serviceTag: project.serviceTag }),
48
+ emitRbacApplicationArtifacts(objects),
49
+ emitSystemWebSocketArtifacts(flows, { includeRelationshipOwnTopic: relationships.length > 0 }),
50
+ emitResourceArtifacts({ objects, relationships, flows })
51
+ ]);
52
+ const custom = await emitCustomFlowApplicationArtifacts(flows, { systemFunctions: system.functions, objects });
53
+ return [
54
+ { scope: 'crud-flow-schemas', managedPaths: dynamicCrudFlowSchemaPaths, artifacts: emitDynamicCrudFlowSchemas({ objects, flows }) },
55
+ { scope: 'relationship-flow-schemas', managedPaths: dynamicRelationshipFlowSchemaPaths, artifacts: emitDynamicRelationshipFlowSchemas() },
56
+ { scope: 'rbac-flow-schemas', managedPaths: rbacFlowSchemaManagedPaths(objects), artifacts: await emitDynamicRbacFlowSchemas({ objects, serviceTag: project.serviceTag }) },
57
+ { scope: 'crud-application', managedPaths: crudApplicationManagedPaths(), artifacts: crud },
58
+ { scope: 'relationship-application', managedPaths: relationshipApplicationManagedPaths(), artifacts: relationship },
59
+ { scope: 'rbac-application', managedPaths: rbacApplicationManagedPaths(objects), artifacts: rbac },
60
+ { scope: 'system-websocket', managedPaths: systemWebSocketManagedPaths(), artifacts: system.artifacts },
61
+ { scope: 'custom-flow-application', managedPaths: customFlowApplicationManagedPaths(flows, { includeYaml: hasSystemWebSocket(flows, { includeRelationshipOwnTopic: relationships.length > 0 }) }), artifacts: custom },
62
+ { scope: 'shared-resources', managedPaths: resourceArtifactPaths, artifacts: resource }
63
+ ];
119
64
  }
120
-
121
- function createSilentLogger() {
122
- return {
123
- debug: () => {},
124
- info: () => {},
125
- warn: () => {},
126
- error: () => {}
127
- };
128
- }
129
-
130
- export { generate };
@@ -0,0 +1,213 @@
1
+ import { constants } from 'node:fs';
2
+ import { copyFile, lstat, mkdir, mkdtemp, readFile, realpath, rename, rm, unlink, writeFile } from 'node:fs/promises';
3
+ import { dirname, join, relative, resolve, sep } from 'node:path';
4
+
5
+ import { normalizeArtifactPaths, validateArtifacts } from './validateArtifacts.js';
6
+ import { mergeHooks } from './mergeHooks.js';
7
+
8
+ const MANAGED_ARTIFACTS_PATH = '.generate-service-code-v2-managed.json';
9
+ const STAGING_PREFIX = '.generate-service-code-v2-stage-';
10
+
11
+ export async function commitArtifacts(plan) {
12
+ if (!plan?.project?.outputPath || !Array.isArray(plan.artifacts)) {
13
+ throw new TypeError('GenerationPlan must include project.outputPath and artifacts');
14
+ }
15
+
16
+ const outputRoot = resolve(plan.project.outputPath);
17
+ const artifacts = validateArtifacts(plan.artifacts);
18
+ await mkdir(outputRoot, { recursive: true });
19
+ const physicalOutputRoot = await realpath(outputRoot);
20
+ const manifestPath = await resolveSafeTarget(physicalOutputRoot, MANAGED_ARTIFACTS_PATH);
21
+ const managedArtifacts = await loadManagedArtifacts(manifestPath);
22
+ const managedScopes = normalizeManagedScopes(plan);
23
+ const stalePaths = staleManagedPaths(managedScopes, managedArtifacts, artifacts);
24
+ const mergedArtifacts = await mergeHooks(physicalOutputRoot, artifacts);
25
+ const stagedRoot = await mkdtemp(join(physicalOutputRoot, STAGING_PREFIX));
26
+
27
+ try {
28
+ const changes = await stageChanges({
29
+ outputRoot: physicalOutputRoot,
30
+ stagedRoot,
31
+ artifacts: mergedArtifacts,
32
+ stalePaths,
33
+ manifestPath,
34
+ manifestContent: managedScopes
35
+ ? managedManifestContent(managedScopes, managedArtifacts, mergedArtifacts)
36
+ : undefined
37
+ });
38
+ const snapshots = await snapshotChanges(changes, stagedRoot);
39
+ try {
40
+ await applyChanges(changes);
41
+ } catch (error) {
42
+ await rollbackChanges(changes, snapshots);
43
+ throw error;
44
+ }
45
+ } finally {
46
+ await rm(stagedRoot, { recursive: true, force: true });
47
+ }
48
+
49
+ return mergedArtifacts.map(({ path }) => ({ path }));
50
+ }
51
+
52
+ function normalizeManagedScopes(plan) {
53
+ if (plan.managedScopes !== undefined) {
54
+ return plan.managedScopes;
55
+ }
56
+ if (plan.managedScope === undefined) {
57
+ return undefined;
58
+ }
59
+ return { [plan.managedScope]: normalizeArtifactPaths(plan.managedPaths ?? []) };
60
+ }
61
+
62
+ function staleManagedPaths(managedScopes, managedArtifacts, artifacts) {
63
+ if (!managedScopes) {
64
+ return [];
65
+ }
66
+ const emittedPaths = new Set(artifacts.map(artifact => artifact.path));
67
+ const stalePaths = new Set();
68
+ for (const [scope, declaredPaths] of Object.entries(managedScopes)) {
69
+ if (!Object.hasOwn(managedArtifacts, scope)) {
70
+ continue;
71
+ }
72
+ for (const path of [...declaredPaths, ...managedArtifacts[scope]]) {
73
+ if (!emittedPaths.has(path)) {
74
+ stalePaths.add(path);
75
+ }
76
+ }
77
+ }
78
+ return [...stalePaths];
79
+ }
80
+
81
+ function managedManifestContent(managedScopes, managedArtifacts, artifacts) {
82
+ const emittedPaths = new Set(artifacts.map(artifact => artifact.path));
83
+ const nextManifest = { ...managedArtifacts };
84
+ for (const [scope, paths] of Object.entries(managedScopes)) {
85
+ nextManifest[scope] = paths.filter(path => emittedPaths.has(path));
86
+ }
87
+ return `${JSON.stringify(nextManifest, null, 2)}\n`;
88
+ }
89
+
90
+ async function stageChanges({ outputRoot, stagedRoot, artifacts, stalePaths, manifestPath, manifestContent }) {
91
+ const changes = [];
92
+ for (const artifact of artifacts) {
93
+ const targetPath = await resolveSafeTarget(outputRoot, artifact.path);
94
+ const stagedPath = await resolveSafeTarget(stagedRoot, artifact.path, { createDirectories: true });
95
+ await writeFile(stagedPath, artifact.content, { encoding: 'utf8', flag: constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | constants.O_NOFOLLOW });
96
+ changes.push({ targetPath, stagedPath });
97
+ }
98
+ for (const path of stalePaths) {
99
+ changes.push({ targetPath: await resolveSafeTarget(outputRoot, path), delete: true });
100
+ }
101
+ if (manifestContent !== undefined) {
102
+ const stagedPath = await resolveSafeTarget(stagedRoot, MANAGED_ARTIFACTS_PATH, { createDirectories: true });
103
+ await writeFile(stagedPath, manifestContent, 'utf8');
104
+ changes.push({ targetPath: manifestPath, stagedPath });
105
+ }
106
+ return changes;
107
+ }
108
+
109
+ async function snapshotChanges(changes, stagedRoot) {
110
+ const snapshots = new Map();
111
+ for (const [index, change] of changes.entries()) {
112
+ try {
113
+ const details = await lstat(change.targetPath);
114
+ if (!details.isFile()) {
115
+ throw new Error(`Artifact target is not a file: ${change.targetPath}`);
116
+ }
117
+ const backupPath = join(stagedRoot, `backup-${index}`);
118
+ await copyFile(change.targetPath, backupPath, constants.COPYFILE_EXCL);
119
+ snapshots.set(change.targetPath, { backupPath });
120
+ } catch (error) {
121
+ if (error.code === 'ENOENT') {
122
+ snapshots.set(change.targetPath, null);
123
+ continue;
124
+ }
125
+ throw error;
126
+ }
127
+ }
128
+ return snapshots;
129
+ }
130
+
131
+ async function applyChanges(changes) {
132
+ for (const change of changes) {
133
+ if (change.delete) {
134
+ await unlink(change.targetPath).catch(ignoreMissingFile);
135
+ continue;
136
+ }
137
+ await mkdir(dirname(change.targetPath), { recursive: true });
138
+ await rename(change.stagedPath, change.targetPath);
139
+ }
140
+ }
141
+
142
+ async function rollbackChanges(changes, snapshots) {
143
+ for (const change of [...changes].reverse()) {
144
+ const snapshot = snapshots.get(change.targetPath);
145
+ if (!snapshot) {
146
+ await unlink(change.targetPath).catch(ignoreMissingFile);
147
+ continue;
148
+ }
149
+ await mkdir(dirname(change.targetPath), { recursive: true });
150
+ await copyFile(snapshot.backupPath, change.targetPath);
151
+ }
152
+ }
153
+
154
+ function ignoreMissingFile(error) {
155
+ if (error.code !== 'ENOENT') {
156
+ throw error;
157
+ }
158
+ }
159
+
160
+ async function loadManagedArtifacts(manifestPath) {
161
+ try {
162
+ const parsed = JSON.parse(await readFile(manifestPath, 'utf8'));
163
+ if (!parsed || Array.isArray(parsed) || typeof parsed !== 'object') {
164
+ throw new TypeError('Managed artifact manifest must be an object');
165
+ }
166
+ for (const paths of Object.values(parsed)) {
167
+ normalizeArtifactPaths(paths);
168
+ }
169
+ return parsed;
170
+ } catch (error) {
171
+ if (error.code === 'ENOENT') {
172
+ return {};
173
+ }
174
+ throw error;
175
+ }
176
+ }
177
+
178
+ async function resolveSafeTarget(outputRoot, artifactPath, { createDirectories = false } = {}) {
179
+ const targetPath = resolve(outputRoot, artifactPath);
180
+ if (relative(outputRoot, targetPath).startsWith('..')) {
181
+ throw new Error(`Artifact path escapes output root: ${artifactPath}`);
182
+ }
183
+
184
+ let currentPath = outputRoot;
185
+ for (const segment of dirname(artifactPath).split(sep).filter(Boolean)) {
186
+ currentPath = join(currentPath, segment);
187
+ try {
188
+ const details = await lstat(currentPath);
189
+ if (details.isSymbolicLink() || !details.isDirectory()) {
190
+ throw new Error(`Artifact path traverses a non-directory: ${artifactPath}`);
191
+ }
192
+ } catch (error) {
193
+ if (error.code !== 'ENOENT') {
194
+ throw error;
195
+ }
196
+ if (!createDirectories) {
197
+ break;
198
+ }
199
+ await mkdir(currentPath, { recursive: true });
200
+ }
201
+ }
202
+
203
+ try {
204
+ if ((await lstat(targetPath)).isSymbolicLink()) {
205
+ throw new Error(`Artifact path targets a symlink: ${artifactPath}`);
206
+ }
207
+ } catch (error) {
208
+ if (error.code !== 'ENOENT') {
209
+ throw error;
210
+ }
211
+ }
212
+ return targetPath;
213
+ }
@@ -0,0 +1,55 @@
1
+ import { lstat, readFile } from 'node:fs/promises';
2
+ import { join, sep } from 'node:path';
3
+
4
+ export async function mergeHooks(outputRoot, artifacts) {
5
+ return Promise.all(artifacts.map(async artifact => ({
6
+ ...artifact,
7
+ content: await mergeHook(outputRoot, artifact)
8
+ })));
9
+ }
10
+
11
+ async function mergeHook(outputRoot, artifact) {
12
+ const parts = artifact.path.split(sep);
13
+ const sourceIndex = parts.lastIndexOf('source');
14
+ if (sourceIndex < 0 || sourceIndex === parts.length - 1) {
15
+ return artifact.content;
16
+ }
17
+
18
+ const hookPath = join(outputRoot, ...parts.slice(0, sourceIndex), 'hook', ...parts.slice(sourceIndex + 1));
19
+ try {
20
+ if (!(await lstat(hookPath)).isFile()) {
21
+ return artifact.content;
22
+ }
23
+ } catch (error) {
24
+ if (error.code === 'ENOENT') {
25
+ return artifact.content;
26
+ }
27
+ throw error;
28
+ }
29
+
30
+ const matchers = hookMatchers(artifact.path);
31
+ if (!matchers) {
32
+ return artifact.content;
33
+ }
34
+
35
+ const hookContent = await readFile(hookPath, 'utf8');
36
+ return artifact.content.replace(matchers.anyTag, (match, tagName) => (
37
+ hookContent.match(matchers.tagPattern(tagName))?.[0] ?? match
38
+ ));
39
+ }
40
+
41
+ function hookMatchers(filePath) {
42
+ if (filePath.endsWith('.js')) {
43
+ return {
44
+ anyTag: /\/\/\(<(\w+)>\)([\s\S]*?)\/\/\(<\/\1>\)/gm,
45
+ tagPattern: name => new RegExp(`\\/\\/\\(<${name}>\\)([\\s\\S]*?)\\/\\/\\(<\\/${name}>\\)`, 'gm')
46
+ };
47
+ }
48
+ if (filePath.endsWith('.yml') || filePath.endsWith('.yaml')) {
49
+ return {
50
+ anyTag: /#<#(\w+)#>([\s\S]*?)#<#\/\1#>/gm,
51
+ tagPattern: name => new RegExp(`#<#${name}#>([\\s\\S]*?)#<#\\/${name}#>`, 'gm')
52
+ };
53
+ }
54
+ return null;
55
+ }
@@ -0,0 +1,62 @@
1
+ import { isAbsolute, normalize } from 'node:path';
2
+
3
+ export function normalizeArtifacts(artifacts) {
4
+ if (!Array.isArray(artifacts)) {
5
+ throw new TypeError('artifacts must be an array');
6
+ }
7
+
8
+ const paths = new Set();
9
+ return Object.freeze(artifacts.map(artifact => {
10
+ if (!artifact || typeof artifact.path !== 'string' || artifact.path.trim() === '') {
11
+ throw new TypeError('Artifact.path must be a non-empty relative path');
12
+ }
13
+ if (isAbsolute(artifact.path)) {
14
+ throw new TypeError(`Artifact.path must be relative: ${artifact.path}`);
15
+ }
16
+ if (typeof artifact.content !== 'string') {
17
+ throw new TypeError(`Artifact.content must be a string: ${artifact.path}`);
18
+ }
19
+
20
+ const path = normalizeArtifactPath(artifact.path);
21
+ if (paths.has(path)) {
22
+ throw new Error(`Duplicate artifact path: ${path}`);
23
+ }
24
+ paths.add(path);
25
+ return Object.freeze({ path, content: artifact.content });
26
+ }));
27
+ }
28
+
29
+ export function validateArtifacts(artifacts) {
30
+ return normalizeArtifacts(artifacts);
31
+ }
32
+
33
+ export function normalizeArtifactPaths(paths) {
34
+ if (!Array.isArray(paths)) {
35
+ throw new TypeError('managedPaths must be an array');
36
+ }
37
+
38
+ const seenPaths = new Set();
39
+ return Object.freeze(paths.map(path => {
40
+ const normalizedPath = normalizeArtifactPath(path);
41
+ if (seenPaths.has(normalizedPath)) {
42
+ throw new Error(`Duplicate artifact path: ${normalizedPath}`);
43
+ }
44
+ seenPaths.add(normalizedPath);
45
+ return normalizedPath;
46
+ }));
47
+ }
48
+
49
+ function normalizeArtifactPath(path) {
50
+ if (typeof path !== 'string' || path.trim() === '') {
51
+ throw new TypeError('Artifact.path must be a non-empty relative path');
52
+ }
53
+ if (isAbsolute(path)) {
54
+ throw new TypeError(`Artifact.path must be relative: ${path}`);
55
+ }
56
+
57
+ const normalizedPath = normalize(path);
58
+ if (normalizedPath === '..' || normalizedPath.startsWith('../')) {
59
+ throw new TypeError(`Artifact.path escapes output root: ${path}`);
60
+ }
61
+ return normalizedPath;
62
+ }
@@ -0,0 +1,50 @@
1
+ import { normalizeArtifactPaths, validateArtifacts } from '../output/validateArtifacts.js';
2
+
3
+ export function buildGenerationPlan(project, artifacts = [], { managedPaths = [], managedScope, managedScopes } = {}) {
4
+ if (!project?.rootPath || !project?.outputPath) {
5
+ throw new TypeError('ProjectModel must include rootPath and outputPath');
6
+ }
7
+ if (managedScope !== undefined && managedScopes !== undefined) {
8
+ throw new TypeError('GenerationPlan must use managedScope or managedScopes, not both');
9
+ }
10
+ return Object.freeze({
11
+ project,
12
+ artifacts: validateArtifacts(artifacts),
13
+ managedPaths: normalizeArtifactPaths(managedPaths),
14
+ managedScope: normalizeManagedScope(managedScope),
15
+ managedScopes: normalizeManagedScopes(managedScopes)
16
+ });
17
+ }
18
+
19
+ function normalizeManagedScope(scope) {
20
+ if (scope === undefined) {
21
+ return undefined;
22
+ }
23
+ if (typeof scope !== 'string' || scope.trim() === '') {
24
+ throw new TypeError('managedScope must be a non-empty string');
25
+ }
26
+ return scope;
27
+ }
28
+
29
+ function normalizeManagedScopes(scopes) {
30
+ if (scopes === undefined) {
31
+ return undefined;
32
+ }
33
+ if (!scopes || Array.isArray(scopes) || typeof scopes !== 'object') {
34
+ throw new TypeError('managedScopes must be an object of scope paths');
35
+ }
36
+ const seenPaths = new Set();
37
+ const normalized = {};
38
+ for (const [scope, paths] of Object.entries(scopes)) {
39
+ const scopeName = normalizeManagedScope(scope);
40
+ const normalizedPaths = normalizeArtifactPaths(paths);
41
+ for (const path of normalizedPaths) {
42
+ if (seenPaths.has(path)) {
43
+ throw new Error(`Artifact path belongs to multiple managed scopes: ${path}`);
44
+ }
45
+ seenPaths.add(path);
46
+ }
47
+ normalized[scopeName] = normalizedPaths;
48
+ }
49
+ return Object.freeze(normalized);
50
+ }