@tailor-platform/erp-kit 0.2.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +193 -69
- package/dist/cli.mjs +1038 -398
- package/package.json +7 -5
- package/skills/erp-kit-app-1-requirements/SKILL.md +27 -17
- package/skills/erp-kit-app-2-requirements-review/SKILL.md +5 -4
- package/skills/erp-kit-app-2-requirements-review/references/best-practices-check.md +10 -1
- package/skills/erp-kit-app-2-requirements-review/references/boundary-consistency-check.md +10 -1
- package/skills/erp-kit-app-3-plan/SKILL.md +31 -34
- package/skills/erp-kit-app-3-plan/references/resolver-extraction.md +22 -36
- package/skills/erp-kit-app-3-plan/references/screen-extraction.md +15 -1
- package/skills/erp-kit-app-3-plan/references/story-extraction.md +8 -2
- package/skills/erp-kit-app-4-plan-review/SKILL.md +1 -10
- package/skills/erp-kit-app-5-impl-backend/SKILL.md +10 -19
- package/skills/erp-kit-app-5-impl-backend/references/app-config.md +1 -22
- package/skills/erp-kit-app-5-impl-backend/references/module-wiring.md +0 -1
- package/skills/erp-kit-app-5-impl-backend/references/resolver-patterns.md +13 -4
- package/skills/erp-kit-app-6-impl-frontend/SKILL.md +5 -0
- package/skills/erp-kit-app-6-impl-frontend/references/pages.md +16 -46
- package/skills/erp-kit-app-7-impl-review/SKILL.md +13 -11
- package/skills/erp-kit-app-7-impl-review/references/resolver-doc-code-parity.md +16 -17
- package/skills/erp-kit-app-shared/SKILL.md +15 -0
- package/skills/erp-kit-app-shared/references/link-format-reference.md +13 -0
- package/skills/erp-kit-app-shared/references/naming-conventions.md +21 -0
- package/skills/erp-kit-app-shared/references/resolver-classification.md +23 -0
- package/skills/erp-kit-app-shared/references/schema-constraints.md +25 -0
- package/skills/erp-kit-module-1-requirements/SKILL.md +7 -13
- package/skills/erp-kit-module-1-requirements/references/feature-doc.md +1 -1
- package/skills/erp-kit-module-2-requirements-review/SKILL.md +21 -5
- package/skills/erp-kit-module-2-requirements-review/references/requirements-report-format.md +19 -0
- package/skills/erp-kit-module-3-plan/SKILL.md +6 -8
- package/skills/erp-kit-module-3-plan/references/naming.md +15 -1
- package/skills/erp-kit-module-4-plan-review/SKILL.md +21 -5
- package/skills/erp-kit-module-4-plan-review/references/parity-report-format.md +15 -0
- package/skills/erp-kit-module-5-impl/SKILL.md +12 -10
- package/skills/erp-kit-module-5-impl/references/generated-code.md +2 -2
- package/skills/erp-kit-module-6-impl-review/SKILL.md +21 -7
- package/skills/erp-kit-module-6-impl-review/references/error-implementation-parity.md +1 -1
- package/skills/erp-kit-module-6-impl-review/references/errors.md +1 -1
- package/skills/erp-kit-module-6-impl-review/references/impl-parity-report-format.md +15 -0
- package/skills/erp-kit-module-shared/SKILL.md +4 -0
- package/skills/erp-kit-module-shared/references/errors.md +1 -1
- package/skills/erp-kit-module-shared/references/queries.md +1 -1
- package/skills/erp-kit-module-shared/references/structure.md +1 -1
- package/skills/erp-kit-update/SKILL.md +2 -2
- package/src/commands/app/index.ts +75 -31
- package/src/commands/check.test.ts +1 -1
- package/src/commands/check.ts +2 -35
- package/src/commands/doc/index.ts +83 -0
- package/src/commands/doc/module.test.ts +119 -0
- package/src/commands/doc/module.ts +114 -0
- package/src/commands/doc/modules.test.ts +103 -0
- package/src/commands/doc/modules.ts +98 -0
- package/src/commands/doc/search.test.ts +94 -0
- package/src/commands/doc/search.ts +111 -0
- package/src/commands/generate-doc.test.ts +63 -0
- package/src/commands/generate-doc.ts +105 -0
- package/src/commands/index.ts +20 -8
- package/src/commands/init-module.test.ts +43 -0
- package/src/commands/init-module.ts +74 -0
- package/src/commands/lib/command-result.ts +30 -0
- package/src/commands/lib/discovery.test.ts +74 -0
- package/src/commands/lib/discovery.ts +106 -0
- package/src/commands/lib/paths.ts +22 -0
- package/src/commands/lib/sync-check-source.test.ts +197 -0
- package/src/commands/lib/sync-check-source.ts +100 -0
- package/src/commands/lib/sync-check-tests.test.ts +178 -0
- package/src/commands/lib/sync-check-tests.ts +69 -0
- package/src/commands/mock/index.ts +11 -6
- package/src/commands/module/generate.ts +39 -14
- package/src/commands/module/index.ts +31 -45
- package/src/commands/parse-doc-test-cases.ts +13 -2
- package/src/commands/sync-check.test.ts +6 -364
- package/src/commands/sync-check.ts +7 -251
- package/src/generator/generate-app-code.test.ts +121 -0
- package/src/generator/generate-app-code.ts +51 -0
- package/src/{commands/scaffold.test.ts → generator/generate-code-boilerplate.test.ts} +19 -89
- package/src/generator/generate-code.test.ts +57 -6
- package/src/generator/generate-code.ts +40 -157
- package/src/generator/generate-errors.ts +34 -0
- package/src/generator/generate-permissions.ts +12 -0
- package/src/generator/generate-shells.ts +28 -0
- package/src/generator/generate-stubs.ts +31 -0
- package/src/generator/parse-resolver-doc.test.ts +89 -0
- package/src/generator/parse-resolver-doc.ts +125 -0
- package/src/generator/scaffold.ts +57 -0
- package/src/generator/stub-templates.test.ts +55 -0
- package/src/generator/stub-templates.ts +145 -0
- package/src/integration.test.ts +2 -2
- package/src/modules/audit/README.md +46 -0
- package/src/modules/audit/command/activateAuditPolicy.generated.ts +6 -0
- package/src/modules/audit/command/activateAuditPolicy.test.ts +186 -0
- package/src/modules/audit/command/activateAuditPolicy.ts +97 -0
- package/src/modules/audit/command/createAuditPolicy.generated.ts +6 -0
- package/src/modules/audit/command/createAuditPolicy.test.ts +395 -0
- package/src/modules/audit/command/createAuditPolicy.ts +131 -0
- package/src/modules/audit/command/deactivateAuditPolicy.generated.ts +6 -0
- package/src/modules/audit/command/deactivateAuditPolicy.test.ts +138 -0
- package/src/modules/audit/command/deactivateAuditPolicy.ts +58 -0
- package/src/modules/audit/command/deleteAuditPolicy.generated.ts +6 -0
- package/src/modules/audit/command/deleteAuditPolicy.test.ts +121 -0
- package/src/modules/audit/command/deleteAuditPolicy.ts +52 -0
- package/src/modules/audit/command/logAuditEvent.generated.ts +6 -0
- package/src/modules/audit/command/logAuditEvent.test.ts +991 -0
- package/src/modules/audit/command/logAuditEvent.ts +357 -0
- package/src/modules/audit/command/reactivateAuditPolicy.generated.ts +6 -0
- package/src/modules/audit/command/reactivateAuditPolicy.test.ts +143 -0
- package/src/modules/audit/command/reactivateAuditPolicy.ts +79 -0
- package/src/modules/audit/command/registerAuditableEntity.generated.ts +6 -0
- package/src/modules/audit/command/registerAuditableEntity.test.ts +268 -0
- package/src/modules/audit/command/registerAuditableEntity.ts +94 -0
- package/src/modules/audit/command/replaceAuditPolicy.generated.ts +6 -0
- package/src/modules/audit/command/replaceAuditPolicy.test.ts +242 -0
- package/src/modules/audit/command/replaceAuditPolicy.ts +91 -0
- package/src/modules/audit/command/updateAuditPolicy.generated.ts +6 -0
- package/src/modules/audit/command/updateAuditPolicy.test.ts +284 -0
- package/src/modules/audit/command/updateAuditPolicy.ts +151 -0
- package/src/modules/audit/db/auditEntry.ts +47 -0
- package/src/modules/audit/db/auditPolicy.ts +33 -0
- package/src/modules/audit/db/auditableEntity.ts +22 -0
- package/src/modules/audit/db/changeDetail.ts +28 -0
- package/src/modules/audit/db/policyFieldRule.ts +23 -0
- package/src/modules/audit/docs/commands/ActivateAuditPolicy.md +69 -0
- package/src/modules/audit/docs/commands/CreateAuditPolicy.md +79 -0
- package/src/modules/audit/docs/commands/DeactivateAuditPolicy.md +55 -0
- package/src/modules/audit/docs/commands/DeleteAuditPolicy.md +55 -0
- package/src/modules/audit/docs/commands/LogAuditEvent.md +137 -0
- package/src/modules/audit/docs/commands/ReactivateAuditPolicy.md +58 -0
- package/src/modules/audit/docs/commands/RegisterAuditableEntity.md +62 -0
- package/src/modules/audit/docs/commands/ReplaceAuditPolicy.md +72 -0
- package/src/modules/audit/docs/commands/UpdateAuditPolicy.md +77 -0
- package/src/modules/audit/docs/features/audit-event-logging.md +126 -0
- package/src/modules/audit/docs/features/audit-policy-configuration.md +135 -0
- package/src/modules/audit/docs/features/field-level-change-tracking.md +95 -0
- package/src/modules/audit/docs/models/AuditEntry.md +55 -0
- package/src/modules/audit/docs/models/AuditPolicy.md +79 -0
- package/src/modules/audit/docs/models/AuditableEntity.md +38 -0
- package/src/modules/audit/docs/models/ChangeDetail.md +55 -0
- package/src/modules/audit/docs/models/PolicyFieldRule.md +45 -0
- package/src/modules/audit/docs/queries/GetAuditEntry.md +49 -0
- package/src/modules/audit/docs/queries/GetAuditPolicy.md +54 -0
- package/src/modules/audit/docs/queries/GetAuditSummary.md +84 -0
- package/src/modules/audit/docs/queries/GetChangeDetails.md +56 -0
- package/src/modules/audit/docs/queries/ListAuditPolicies.md +58 -0
- package/src/modules/audit/docs/queries/SearchAuditEntries.md +91 -0
- package/src/modules/audit/generated/kysely-tailordb.ts +92 -0
- package/src/modules/audit/index.ts +2 -0
- package/src/modules/audit/lib/_db_deps.ts +13 -0
- package/src/modules/audit/lib/errors.generated.ts +120 -0
- package/src/modules/audit/lib/permissions.generated.ts +14 -0
- package/src/modules/audit/lib/types.ts +28 -0
- package/src/modules/audit/module.ts +57 -0
- package/src/modules/audit/permissions.ts +39 -0
- package/src/modules/audit/query/getAuditEntry.generated.ts +5 -0
- package/src/modules/audit/query/getAuditEntry.test.ts +123 -0
- package/src/modules/audit/query/getAuditEntry.ts +36 -0
- package/src/modules/audit/query/getAuditPolicy.generated.ts +5 -0
- package/src/modules/audit/query/getAuditPolicy.test.ts +169 -0
- package/src/modules/audit/query/getAuditPolicy.ts +42 -0
- package/src/modules/audit/query/getAuditSummary.generated.ts +5 -0
- package/src/modules/audit/query/getAuditSummary.test.ts +632 -0
- package/src/modules/audit/query/getAuditSummary.ts +164 -0
- package/src/modules/audit/query/getChangeDetails.generated.ts +5 -0
- package/src/modules/audit/query/getChangeDetails.test.ts +195 -0
- package/src/modules/audit/query/getChangeDetails.ts +42 -0
- package/src/modules/audit/query/listAuditPolicies.generated.ts +5 -0
- package/src/modules/audit/query/listAuditPolicies.test.ts +239 -0
- package/src/modules/audit/query/listAuditPolicies.ts +100 -0
- package/src/modules/audit/query/searchAuditEntries.generated.ts +5 -0
- package/src/modules/audit/query/searchAuditEntries.test.ts +424 -0
- package/src/modules/audit/query/searchAuditEntries.ts +121 -0
- package/src/modules/audit/tailor.config.ts +13 -0
- package/src/modules/audit/tailor.d.ts +13 -0
- package/src/modules/audit/testing/fixtures.ts +215 -0
- package/src/modules/business-partner/README.md +60 -0
- package/src/modules/business-partner/command/.gitkeep +0 -0
- package/src/modules/business-partner/command/activatePartner.generated.ts +6 -0
- package/src/modules/business-partner/command/activatePartner.test.ts +59 -0
- package/src/modules/business-partner/command/activatePartner.ts +45 -0
- package/src/modules/business-partner/command/assignRoleToPartner.generated.ts +6 -0
- package/src/modules/business-partner/command/assignRoleToPartner.test.ts +113 -0
- package/src/modules/business-partner/command/assignRoleToPartner.ts +72 -0
- package/src/modules/business-partner/command/createContactPerson.generated.ts +6 -0
- package/src/modules/business-partner/command/createContactPerson.test.ts +193 -0
- package/src/modules/business-partner/command/createContactPerson.ts +98 -0
- package/src/modules/business-partner/command/createPartner.generated.ts +6 -0
- package/src/modules/business-partner/command/createPartner.test.ts +179 -0
- package/src/modules/business-partner/command/createPartner.ts +83 -0
- package/src/modules/business-partner/command/createPartnerAddress.generated.ts +6 -0
- package/src/modules/business-partner/command/createPartnerAddress.test.ts +195 -0
- package/src/modules/business-partner/command/createPartnerAddress.ts +119 -0
- package/src/modules/business-partner/command/createPartnerBankAccount.generated.ts +6 -0
- package/src/modules/business-partner/command/createPartnerBankAccount.test.ts +297 -0
- package/src/modules/business-partner/command/createPartnerBankAccount.ts +114 -0
- package/src/modules/business-partner/command/createPartnerIdentification.generated.ts +6 -0
- package/src/modules/business-partner/command/createPartnerIdentification.test.ts +255 -0
- package/src/modules/business-partner/command/createPartnerIdentification.ts +97 -0
- package/src/modules/business-partner/command/deactivateContactPerson.generated.ts +6 -0
- package/src/modules/business-partner/command/deactivateContactPerson.test.ts +70 -0
- package/src/modules/business-partner/command/deactivateContactPerson.ts +54 -0
- package/src/modules/business-partner/command/deactivatePartner.generated.ts +6 -0
- package/src/modules/business-partner/command/deactivatePartner.test.ts +59 -0
- package/src/modules/business-partner/command/deactivatePartner.ts +46 -0
- package/src/modules/business-partner/command/deleteContactPerson.generated.ts +6 -0
- package/src/modules/business-partner/command/deleteContactPerson.test.ts +61 -0
- package/src/modules/business-partner/command/deleteContactPerson.ts +48 -0
- package/src/modules/business-partner/command/deletePartner.generated.ts +6 -0
- package/src/modules/business-partner/command/deletePartner.test.ts +58 -0
- package/src/modules/business-partner/command/deletePartner.ts +46 -0
- package/src/modules/business-partner/command/deletePartnerAddress.generated.ts +6 -0
- package/src/modules/business-partner/command/deletePartnerAddress.test.ts +74 -0
- package/src/modules/business-partner/command/deletePartnerAddress.ts +52 -0
- package/src/modules/business-partner/command/deletePartnerBankAccount.generated.ts +6 -0
- package/src/modules/business-partner/command/deletePartnerBankAccount.test.ts +55 -0
- package/src/modules/business-partner/command/deletePartnerBankAccount.ts +36 -0
- package/src/modules/business-partner/command/deletePartnerIdentification.generated.ts +6 -0
- package/src/modules/business-partner/command/deletePartnerIdentification.test.ts +47 -0
- package/src/modules/business-partner/command/deletePartnerIdentification.ts +37 -0
- package/src/modules/business-partner/command/reactivateContactPerson.generated.ts +6 -0
- package/src/modules/business-partner/command/reactivateContactPerson.test.ts +48 -0
- package/src/modules/business-partner/command/reactivateContactPerson.ts +48 -0
- package/src/modules/business-partner/command/reactivatePartner.generated.ts +6 -0
- package/src/modules/business-partner/command/reactivatePartner.test.ts +59 -0
- package/src/modules/business-partner/command/reactivatePartner.ts +46 -0
- package/src/modules/business-partner/command/removeRoleFromPartner.generated.ts +6 -0
- package/src/modules/business-partner/command/removeRoleFromPartner.test.ts +82 -0
- package/src/modules/business-partner/command/removeRoleFromPartner.ts +73 -0
- package/src/modules/business-partner/command/setDefaultPartnerAddress.generated.ts +6 -0
- package/src/modules/business-partner/command/setDefaultPartnerAddress.test.ts +60 -0
- package/src/modules/business-partner/command/setDefaultPartnerAddress.ts +48 -0
- package/src/modules/business-partner/command/setDefaultPartnerBankAccount.generated.ts +6 -0
- package/src/modules/business-partner/command/setDefaultPartnerBankAccount.test.ts +56 -0
- package/src/modules/business-partner/command/setDefaultPartnerBankAccount.ts +51 -0
- package/src/modules/business-partner/command/setPrimaryContactPerson.generated.ts +6 -0
- package/src/modules/business-partner/command/setPrimaryContactPerson.test.ts +63 -0
- package/src/modules/business-partner/command/setPrimaryContactPerson.ts +55 -0
- package/src/modules/business-partner/command/updateContactPerson.generated.ts +6 -0
- package/src/modules/business-partner/command/updateContactPerson.test.ts +193 -0
- package/src/modules/business-partner/command/updateContactPerson.ts +92 -0
- package/src/modules/business-partner/command/updatePartner.generated.ts +6 -0
- package/src/modules/business-partner/command/updatePartner.test.ts +101 -0
- package/src/modules/business-partner/command/updatePartner.ts +76 -0
- package/src/modules/business-partner/command/updatePartnerAddress.generated.ts +6 -0
- package/src/modules/business-partner/command/updatePartnerAddress.test.ts +148 -0
- package/src/modules/business-partner/command/updatePartnerAddress.ts +64 -0
- package/src/modules/business-partner/command/updatePartnerBankAccount.generated.ts +6 -0
- package/src/modules/business-partner/command/updatePartnerBankAccount.test.ts +249 -0
- package/src/modules/business-partner/command/updatePartnerBankAccount.ts +109 -0
- package/src/modules/business-partner/command/updatePartnerIdentification.generated.ts +6 -0
- package/src/modules/business-partner/command/updatePartnerIdentification.test.ts +162 -0
- package/src/modules/business-partner/command/updatePartnerIdentification.ts +105 -0
- package/src/modules/business-partner/db/.gitkeep +0 -0
- package/src/modules/business-partner/db/businessPartner.ts +59 -0
- package/src/modules/business-partner/db/contactPerson.ts +49 -0
- package/src/modules/business-partner/db/partnerAddress.ts +45 -0
- package/src/modules/business-partner/db/partnerBankAccount.ts +53 -0
- package/src/modules/business-partner/db/partnerIdentification.ts +53 -0
- package/src/modules/business-partner/db/partnerRole.ts +43 -0
- package/src/modules/business-partner/docs/commands/ActivatePartner.md +39 -0
- package/src/modules/business-partner/docs/commands/AssignRoleToPartner.md +49 -0
- package/src/modules/business-partner/docs/commands/CreateContactPerson.md +59 -0
- package/src/modules/business-partner/docs/commands/CreatePartner.md +54 -0
- package/src/modules/business-partner/docs/commands/CreatePartnerAddress.md +60 -0
- package/src/modules/business-partner/docs/commands/CreatePartnerBankAccount.md +68 -0
- package/src/modules/business-partner/docs/commands/CreatePartnerIdentification.md +59 -0
- package/src/modules/business-partner/docs/commands/DeactivateContactPerson.md +42 -0
- package/src/modules/business-partner/docs/commands/DeactivatePartner.md +39 -0
- package/src/modules/business-partner/docs/commands/DeleteContactPerson.md +43 -0
- package/src/modules/business-partner/docs/commands/DeletePartner.md +40 -0
- package/src/modules/business-partner/docs/commands/DeletePartnerAddress.md +40 -0
- package/src/modules/business-partner/docs/commands/DeletePartnerBankAccount.md +35 -0
- package/src/modules/business-partner/docs/commands/DeletePartnerIdentification.md +33 -0
- package/src/modules/business-partner/docs/commands/ReactivateContactPerson.md +38 -0
- package/src/modules/business-partner/docs/commands/ReactivatePartner.md +39 -0
- package/src/modules/business-partner/docs/commands/RemoveRoleFromPartner.md +46 -0
- package/src/modules/business-partner/docs/commands/SetDefaultPartnerAddress.md +38 -0
- package/src/modules/business-partner/docs/commands/SetDefaultPartnerBankAccount.md +38 -0
- package/src/modules/business-partner/docs/commands/SetPrimaryContactPerson.md +43 -0
- package/src/modules/business-partner/docs/commands/UpdateContactPerson.md +66 -0
- package/src/modules/business-partner/docs/commands/UpdatePartner.md +48 -0
- package/src/modules/business-partner/docs/commands/UpdatePartnerAddress.md +46 -0
- package/src/modules/business-partner/docs/commands/UpdatePartnerBankAccount.md +64 -0
- package/src/modules/business-partner/docs/commands/UpdatePartnerIdentification.md +52 -0
- package/src/modules/business-partner/docs/features/contact-person-management.md +70 -0
- package/src/modules/business-partner/docs/features/partner-address-management.md +96 -0
- package/src/modules/business-partner/docs/features/partner-bank-account.md +70 -0
- package/src/modules/business-partner/docs/features/partner-identification.md +76 -0
- package/src/modules/business-partner/docs/features/partner-lifecycle.md +59 -0
- package/src/modules/business-partner/docs/features/partner-role-classification.md +73 -0
- package/src/modules/business-partner/docs/models/BusinessPartner.md +64 -0
- package/src/modules/business-partner/docs/models/ContactPerson.md +62 -0
- package/src/modules/business-partner/docs/models/PartnerAddress.md +52 -0
- package/src/modules/business-partner/docs/models/PartnerBankAccount.md +50 -0
- package/src/modules/business-partner/docs/models/PartnerIdentification.md +46 -0
- package/src/modules/business-partner/docs/models/PartnerRole.md +42 -0
- package/src/modules/business-partner/docs/queries/GetContactPerson.md +34 -0
- package/src/modules/business-partner/docs/queries/GetDefaultPartnerAddress.md +40 -0
- package/src/modules/business-partner/docs/queries/GetDefaultPartnerBankAccount.md +36 -0
- package/src/modules/business-partner/docs/queries/GetPartner.md +35 -0
- package/src/modules/business-partner/docs/queries/GetPartnerAddress.md +34 -0
- package/src/modules/business-partner/docs/queries/GetPartnerBankAccount.md +34 -0
- package/src/modules/business-partner/docs/queries/GetPartnerIdentification.md +34 -0
- package/src/modules/business-partner/docs/queries/GetPartnerRole.md +34 -0
- package/src/modules/business-partner/docs/queries/GetPrimaryContactPerson.md +36 -0
- package/src/modules/business-partner/docs/queries/ListContactPersonsByPartner.md +39 -0
- package/src/modules/business-partner/docs/queries/ListPartnerAddressesByPartner.md +41 -0
- package/src/modules/business-partner/docs/queries/ListPartnerBankAccountsByPartner.md +39 -0
- package/src/modules/business-partner/docs/queries/ListPartnerIdentificationsByPartner.md +41 -0
- package/src/modules/business-partner/docs/queries/ListPartnersByRole.md +47 -0
- package/src/modules/business-partner/executor/.gitkeep +0 -0
- package/src/modules/business-partner/generated/.gitkeep +0 -0
- package/src/modules/business-partner/generated/enums.ts +60 -0
- package/src/modules/business-partner/generated/kysely-tailordb.ts +114 -0
- package/src/modules/business-partner/index.ts +2 -0
- package/src/modules/business-partner/lib/_db_deps.ts +17 -0
- package/src/modules/business-partner/lib/errors.generated.ts +172 -0
- package/src/modules/business-partner/lib/errors.ts +2 -0
- package/src/modules/business-partner/lib/permissions.generated.ts +30 -0
- package/src/modules/business-partner/lib/types.ts +53 -0
- package/src/modules/business-partner/module.ts +181 -0
- package/src/modules/business-partner/permissions.ts +3 -0
- package/src/modules/business-partner/query/.gitkeep +0 -0
- package/src/modules/business-partner/query/getContactPerson.generated.ts +5 -0
- package/src/modules/business-partner/query/getContactPerson.test.ts +31 -0
- package/src/modules/business-partner/query/getContactPerson.ts +16 -0
- package/src/modules/business-partner/query/getDefaultPartnerAddress.generated.ts +5 -0
- package/src/modules/business-partner/query/getDefaultPartnerAddress.test.ts +45 -0
- package/src/modules/business-partner/query/getDefaultPartnerAddress.ts +30 -0
- package/src/modules/business-partner/query/getDefaultPartnerBankAccount.generated.ts +5 -0
- package/src/modules/business-partner/query/getDefaultPartnerBankAccount.test.ts +43 -0
- package/src/modules/business-partner/query/getDefaultPartnerBankAccount.ts +17 -0
- package/src/modules/business-partner/query/getPartner.generated.ts +5 -0
- package/src/modules/business-partner/query/getPartner.test.ts +31 -0
- package/src/modules/business-partner/query/getPartner.ts +16 -0
- package/src/modules/business-partner/query/getPartnerAddress.generated.ts +5 -0
- package/src/modules/business-partner/query/getPartnerAddress.test.ts +31 -0
- package/src/modules/business-partner/query/getPartnerAddress.ts +16 -0
- package/src/modules/business-partner/query/getPartnerBankAccount.generated.ts +5 -0
- package/src/modules/business-partner/query/getPartnerBankAccount.test.ts +31 -0
- package/src/modules/business-partner/query/getPartnerBankAccount.ts +16 -0
- package/src/modules/business-partner/query/getPartnerIdentification.generated.ts +5 -0
- package/src/modules/business-partner/query/getPartnerIdentification.test.ts +31 -0
- package/src/modules/business-partner/query/getPartnerIdentification.ts +16 -0
- package/src/modules/business-partner/query/getPartnerRole.generated.ts +5 -0
- package/src/modules/business-partner/query/getPartnerRole.test.ts +31 -0
- package/src/modules/business-partner/query/getPartnerRole.ts +19 -0
- package/src/modules/business-partner/query/getPrimaryContactPerson.generated.ts +5 -0
- package/src/modules/business-partner/query/getPrimaryContactPerson.test.ts +43 -0
- package/src/modules/business-partner/query/getPrimaryContactPerson.ts +17 -0
- package/src/modules/business-partner/query/listContactPersonsByPartner.generated.ts +5 -0
- package/src/modules/business-partner/query/listContactPersonsByPartner.test.ts +77 -0
- package/src/modules/business-partner/query/listContactPersonsByPartner.ts +32 -0
- package/src/modules/business-partner/query/listPartnerAddressesByPartner.generated.ts +5 -0
- package/src/modules/business-partner/query/listPartnerAddressesByPartner.test.ts +71 -0
- package/src/modules/business-partner/query/listPartnerAddressesByPartner.ts +37 -0
- package/src/modules/business-partner/query/listPartnerBankAccountsByPartner.generated.ts +5 -0
- package/src/modules/business-partner/query/listPartnerBankAccountsByPartner.test.ts +59 -0
- package/src/modules/business-partner/query/listPartnerBankAccountsByPartner.ts +32 -0
- package/src/modules/business-partner/query/listPartnerIdentificationsByPartner.generated.ts +5 -0
- package/src/modules/business-partner/query/listPartnerIdentificationsByPartner.test.ts +72 -0
- package/src/modules/business-partner/query/listPartnerIdentificationsByPartner.ts +40 -0
- package/src/modules/business-partner/query/listPartnersByRole.generated.ts +5 -0
- package/src/modules/business-partner/query/listPartnersByRole.test.ts +103 -0
- package/src/modules/business-partner/query/listPartnersByRole.ts +47 -0
- package/src/modules/business-partner/tailor.config.ts +13 -0
- package/src/modules/business-partner/tailor.d.ts +13 -0
- package/src/modules/business-partner/testing/fixtures.ts +204 -0
- package/src/modules/coa-management/README.md +61 -0
- package/src/modules/coa-management/command/.gitkeep +0 -0
- package/src/modules/coa-management/command/activateAccount.generated.ts +6 -0
- package/src/modules/coa-management/command/activateAccount.test.ts +125 -0
- package/src/modules/coa-management/command/activateAccount.ts +105 -0
- package/src/modules/coa-management/command/activateChartOfAccounts.generated.ts +6 -0
- package/src/modules/coa-management/command/activateChartOfAccounts.test.ts +113 -0
- package/src/modules/coa-management/command/activateChartOfAccounts.ts +104 -0
- package/src/modules/coa-management/command/createAccount.generated.ts +6 -0
- package/src/modules/coa-management/command/createAccount.test.ts +767 -0
- package/src/modules/coa-management/command/createAccount.ts +247 -0
- package/src/modules/coa-management/command/createAccountGroup.generated.ts +6 -0
- package/src/modules/coa-management/command/createAccountGroup.test.ts +494 -0
- package/src/modules/coa-management/command/createAccountGroup.ts +207 -0
- package/src/modules/coa-management/command/createChartOfAccounts.generated.ts +6 -0
- package/src/modules/coa-management/command/createChartOfAccounts.test.ts +502 -0
- package/src/modules/coa-management/command/createChartOfAccounts.ts +267 -0
- package/src/modules/coa-management/command/deactivateAccount.generated.ts +6 -0
- package/src/modules/coa-management/command/deactivateAccount.test.ts +199 -0
- package/src/modules/coa-management/command/deactivateAccount.ts +142 -0
- package/src/modules/coa-management/command/deactivateChartOfAccounts.generated.ts +6 -0
- package/src/modules/coa-management/command/deactivateChartOfAccounts.test.ts +91 -0
- package/src/modules/coa-management/command/deactivateChartOfAccounts.ts +88 -0
- package/src/modules/coa-management/command/deleteAccount.generated.ts +6 -0
- package/src/modules/coa-management/command/deleteAccount.test.ts +122 -0
- package/src/modules/coa-management/command/deleteAccount.ts +103 -0
- package/src/modules/coa-management/command/deleteAccountGroup.generated.ts +6 -0
- package/src/modules/coa-management/command/deleteAccountGroup.test.ts +120 -0
- package/src/modules/coa-management/command/deleteAccountGroup.ts +113 -0
- package/src/modules/coa-management/command/deleteChartOfAccounts.generated.ts +6 -0
- package/src/modules/coa-management/command/deleteChartOfAccounts.test.ts +154 -0
- package/src/modules/coa-management/command/deleteChartOfAccounts.ts +133 -0
- package/src/modules/coa-management/command/moveAccountGroup.generated.ts +6 -0
- package/src/modules/coa-management/command/moveAccountGroup.test.ts +199 -0
- package/src/modules/coa-management/command/moveAccountGroup.ts +145 -0
- package/src/modules/coa-management/command/reactivateAccount.generated.ts +6 -0
- package/src/modules/coa-management/command/reactivateAccount.test.ts +126 -0
- package/src/modules/coa-management/command/reactivateAccount.ts +123 -0
- package/src/modules/coa-management/command/updateAccount.generated.ts +6 -0
- package/src/modules/coa-management/command/updateAccount.test.ts +669 -0
- package/src/modules/coa-management/command/updateAccount.ts +370 -0
- package/src/modules/coa-management/command/updateAccountGroup.generated.ts +6 -0
- package/src/modules/coa-management/command/updateAccountGroup.test.ts +253 -0
- package/src/modules/coa-management/command/updateAccountGroup.ts +191 -0
- package/src/modules/coa-management/command/updateChartOfAccounts.generated.ts +6 -0
- package/src/modules/coa-management/command/updateChartOfAccounts.test.ts +153 -0
- package/src/modules/coa-management/command/updateChartOfAccounts.ts +133 -0
- package/src/modules/coa-management/db/.gitkeep +0 -0
- package/src/modules/coa-management/db/account.ts +119 -0
- package/src/modules/coa-management/db/accountGroup.ts +57 -0
- package/src/modules/coa-management/db/chartOfAccounts.ts +55 -0
- package/src/modules/coa-management/docs/commands/ActivateAccount.md +49 -0
- package/src/modules/coa-management/docs/commands/ActivateChartOfAccounts.md +47 -0
- package/src/modules/coa-management/docs/commands/CreateAccount.md +94 -0
- package/src/modules/coa-management/docs/commands/CreateAccountGroup.md +70 -0
- package/src/modules/coa-management/docs/commands/CreateChartOfAccounts.md +72 -0
- package/src/modules/coa-management/docs/commands/DeactivateAccount.md +65 -0
- package/src/modules/coa-management/docs/commands/DeactivateChartOfAccounts.md +44 -0
- package/src/modules/coa-management/docs/commands/DeleteAccount.md +52 -0
- package/src/modules/coa-management/docs/commands/DeleteAccountGroup.md +50 -0
- package/src/modules/coa-management/docs/commands/DeleteChartOfAccounts.md +48 -0
- package/src/modules/coa-management/docs/commands/MoveAccountGroup.md +57 -0
- package/src/modules/coa-management/docs/commands/ReactivateAccount.md +50 -0
- package/src/modules/coa-management/docs/commands/UpdateAccount.md +102 -0
- package/src/modules/coa-management/docs/commands/UpdateAccountGroup.md +62 -0
- package/src/modules/coa-management/docs/commands/UpdateChartOfAccounts.md +49 -0
- package/src/modules/coa-management/docs/features/account-group-hierarchy.md +81 -0
- package/src/modules/coa-management/docs/features/account-lifecycle.md +80 -0
- package/src/modules/coa-management/docs/features/account-management.md +114 -0
- package/src/modules/coa-management/docs/features/chart-of-accounts-setup.md +86 -0
- package/src/modules/coa-management/docs/models/Account.md +84 -0
- package/src/modules/coa-management/docs/models/AccountGroup.md +55 -0
- package/src/modules/coa-management/docs/models/ChartOfAccounts.md +65 -0
- package/src/modules/coa-management/docs/queries/DetectCircularReference.md +52 -0
- package/src/modules/coa-management/docs/queries/GetAccount.md +42 -0
- package/src/modules/coa-management/docs/queries/GetAccountGroup.md +42 -0
- package/src/modules/coa-management/docs/queries/GetChartOfAccounts.md +48 -0
- package/src/modules/coa-management/docs/queries/ListAccountGroups.md +42 -0
- package/src/modules/coa-management/docs/queries/ListAccounts.md +54 -0
- package/src/modules/coa-management/docs/queries/ListUnassignedAccounts.md +40 -0
- package/src/modules/coa-management/executor/.gitkeep +0 -0
- package/src/modules/coa-management/generated/.gitkeep +0 -0
- package/src/modules/coa-management/generated/enums.ts +45 -0
- package/src/modules/coa-management/generated/kysely-tailordb.ts +81 -0
- package/src/modules/coa-management/index.ts +2 -0
- package/src/modules/coa-management/lib/_db_deps.ts +17 -0
- package/src/modules/coa-management/lib/errors.generated.ts +162 -0
- package/src/modules/coa-management/lib/errors.ts +0 -0
- package/src/modules/coa-management/lib/permissions.generated.ts +20 -0
- package/src/modules/coa-management/lib/types.ts +22 -0
- package/src/modules/coa-management/module.ts +136 -0
- package/src/modules/coa-management/permissions.ts +3 -0
- package/src/modules/coa-management/query/.gitkeep +0 -0
- package/src/modules/coa-management/query/detectCircularReference.generated.ts +5 -0
- package/src/modules/coa-management/query/detectCircularReference.test.ts +88 -0
- package/src/modules/coa-management/query/detectCircularReference.ts +46 -0
- package/src/modules/coa-management/query/getAccount.generated.ts +5 -0
- package/src/modules/coa-management/query/getAccount.test.ts +55 -0
- package/src/modules/coa-management/query/getAccount.ts +25 -0
- package/src/modules/coa-management/query/getAccountGroup.generated.ts +5 -0
- package/src/modules/coa-management/query/getAccountGroup.test.ts +55 -0
- package/src/modules/coa-management/query/getAccountGroup.ts +25 -0
- package/src/modules/coa-management/query/getChartOfAccounts.generated.ts +5 -0
- package/src/modules/coa-management/query/getChartOfAccounts.test.ts +79 -0
- package/src/modules/coa-management/query/getChartOfAccounts.ts +28 -0
- package/src/modules/coa-management/query/listAccountGroups.generated.ts +5 -0
- package/src/modules/coa-management/query/listAccountGroups.test.ts +72 -0
- package/src/modules/coa-management/query/listAccountGroups.ts +49 -0
- package/src/modules/coa-management/query/listAccounts.generated.ts +5 -0
- package/src/modules/coa-management/query/listAccounts.test.ts +136 -0
- package/src/modules/coa-management/query/listAccounts.ts +82 -0
- package/src/modules/coa-management/query/listUnassignedAccounts.generated.ts +5 -0
- package/src/modules/coa-management/query/listUnassignedAccounts.test.ts +96 -0
- package/src/modules/coa-management/query/listUnassignedAccounts.ts +39 -0
- package/src/modules/coa-management/tailor.config.ts +13 -0
- package/src/modules/coa-management/tailor.d.ts +13 -0
- package/src/modules/coa-management/testing/fixtures.ts +201 -0
- package/src/modules/item-management/README.md +1 -1
- package/src/modules/organization/README.md +57 -0
- package/src/modules/organization/command/.gitkeep +0 -0
- package/src/modules/organization/command/activateCompany.generated.ts +6 -0
- package/src/modules/organization/command/activateCompany.test.ts +184 -0
- package/src/modules/organization/command/activateCompany.ts +92 -0
- package/src/modules/organization/command/createCompany.generated.ts +6 -0
- package/src/modules/organization/command/createCompany.test.ts +156 -0
- package/src/modules/organization/command/createCompany.ts +80 -0
- package/src/modules/organization/command/createDepartment.generated.ts +6 -0
- package/src/modules/organization/command/createDepartment.test.ts +239 -0
- package/src/modules/organization/command/createDepartment.ts +98 -0
- package/src/modules/organization/command/createSite.generated.ts +6 -0
- package/src/modules/organization/command/createSite.test.ts +262 -0
- package/src/modules/organization/command/createSite.ts +155 -0
- package/src/modules/organization/command/deactivateCompany.generated.ts +6 -0
- package/src/modules/organization/command/deactivateCompany.test.ts +58 -0
- package/src/modules/organization/command/deactivateCompany.ts +47 -0
- package/src/modules/organization/command/deactivateDepartment.generated.ts +6 -0
- package/src/modules/organization/command/deactivateDepartment.test.ts +115 -0
- package/src/modules/organization/command/deactivateDepartment.ts +63 -0
- package/src/modules/organization/command/deactivateSite.generated.ts +6 -0
- package/src/modules/organization/command/deactivateSite.test.ts +53 -0
- package/src/modules/organization/command/deactivateSite.ts +47 -0
- package/src/modules/organization/command/deleteCompany.generated.ts +6 -0
- package/src/modules/organization/command/deleteCompany.test.ts +99 -0
- package/src/modules/organization/command/deleteCompany.ts +66 -0
- package/src/modules/organization/command/reactivateCompany.generated.ts +6 -0
- package/src/modules/organization/command/reactivateCompany.test.ts +58 -0
- package/src/modules/organization/command/reactivateCompany.ts +47 -0
- package/src/modules/organization/command/reactivateDepartment.generated.ts +6 -0
- package/src/modules/organization/command/reactivateDepartment.test.ts +59 -0
- package/src/modules/organization/command/reactivateDepartment.ts +47 -0
- package/src/modules/organization/command/reactivateSite.generated.ts +6 -0
- package/src/modules/organization/command/reactivateSite.test.ts +53 -0
- package/src/modules/organization/command/reactivateSite.ts +47 -0
- package/src/modules/organization/command/updateCompany.generated.ts +6 -0
- package/src/modules/organization/command/updateCompany.test.ts +239 -0
- package/src/modules/organization/command/updateCompany.ts +127 -0
- package/src/modules/organization/command/updateDepartment.generated.ts +6 -0
- package/src/modules/organization/command/updateDepartment.test.ts +232 -0
- package/src/modules/organization/command/updateDepartment.ts +120 -0
- package/src/modules/organization/command/updateSite.generated.ts +6 -0
- package/src/modules/organization/command/updateSite.test.ts +274 -0
- package/src/modules/organization/command/updateSite.ts +176 -0
- package/src/modules/organization/db/.gitkeep +0 -0
- package/src/modules/organization/db/company.ts +44 -0
- package/src/modules/organization/db/department.ts +46 -0
- package/src/modules/organization/db/site.ts +44 -0
- package/src/modules/organization/docs/commands/ActivateCompany.md +62 -0
- package/src/modules/organization/docs/commands/CreateCompany.md +49 -0
- package/src/modules/organization/docs/commands/CreateDepartment.md +62 -0
- package/src/modules/organization/docs/commands/CreateSite.md +74 -0
- package/src/modules/organization/docs/commands/DeactivateCompany.md +40 -0
- package/src/modules/organization/docs/commands/DeactivateDepartment.md +44 -0
- package/src/modules/organization/docs/commands/DeactivateSite.md +38 -0
- package/src/modules/organization/docs/commands/DeleteCompany.md +50 -0
- package/src/modules/organization/docs/commands/ReactivateCompany.md +39 -0
- package/src/modules/organization/docs/commands/ReactivateDepartment.md +37 -0
- package/src/modules/organization/docs/commands/ReactivateSite.md +37 -0
- package/src/modules/organization/docs/commands/UpdateCompany.md +58 -0
- package/src/modules/organization/docs/commands/UpdateDepartment.md +64 -0
- package/src/modules/organization/docs/commands/UpdateSite.md +80 -0
- package/src/modules/organization/docs/features/company-lifecycle.md +76 -0
- package/src/modules/organization/docs/features/department-management.md +66 -0
- package/src/modules/organization/docs/features/site-management.md +86 -0
- package/src/modules/organization/docs/models/Company.md +60 -0
- package/src/modules/organization/docs/models/Department.md +57 -0
- package/src/modules/organization/docs/models/Site.md +57 -0
- package/src/modules/organization/docs/queries/DetectDepartmentCircularReference.md +50 -0
- package/src/modules/organization/docs/queries/GetCompany.md +40 -0
- package/src/modules/organization/docs/queries/GetDepartment.md +44 -0
- package/src/modules/organization/docs/queries/GetDepartmentChildren.md +40 -0
- package/src/modules/organization/docs/queries/GetSite.md +37 -0
- package/src/modules/organization/docs/queries/ListDepartmentsByCompany.md +54 -0
- package/src/modules/organization/docs/queries/ListSitesByCompany.md +54 -0
- package/src/modules/organization/executor/.gitkeep +0 -0
- package/src/modules/organization/generated/.gitkeep +0 -0
- package/src/modules/organization/generated/kysely-tailordb.ts +77 -0
- package/src/modules/organization/index.ts +2 -0
- package/src/modules/organization/lib/_db_deps.ts +10 -0
- package/src/modules/organization/lib/errors.generated.ts +117 -0
- package/src/modules/organization/lib/errors.ts +1 -0
- package/src/modules/organization/lib/permissions.generated.ts +19 -0
- package/src/modules/organization/lib/types.ts +16 -0
- package/src/modules/organization/module.ts +89 -0
- package/src/modules/organization/permissions.ts +3 -0
- package/src/modules/organization/query/.gitkeep +0 -0
- package/src/modules/organization/query/detectDepartmentCircularReference.generated.ts +5 -0
- package/src/modules/organization/query/detectDepartmentCircularReference.test.ts +102 -0
- package/src/modules/organization/query/detectDepartmentCircularReference.ts +27 -0
- package/src/modules/organization/query/getCompany.generated.ts +5 -0
- package/src/modules/organization/query/getCompany.test.ts +70 -0
- package/src/modules/organization/query/getCompany.ts +16 -0
- package/src/modules/organization/query/getDepartment.generated.ts +5 -0
- package/src/modules/organization/query/getDepartment.test.ts +85 -0
- package/src/modules/organization/query/getDepartment.ts +17 -0
- package/src/modules/organization/query/getDepartmentChildren.generated.ts +5 -0
- package/src/modules/organization/query/getDepartmentChildren.test.ts +75 -0
- package/src/modules/organization/query/getDepartmentChildren.ts +21 -0
- package/src/modules/organization/query/getSite.generated.ts +5 -0
- package/src/modules/organization/query/getSite.test.ts +55 -0
- package/src/modules/organization/query/getSite.ts +16 -0
- package/src/modules/organization/query/listDepartmentsByCompany.generated.ts +5 -0
- package/src/modules/organization/query/listDepartmentsByCompany.test.ts +124 -0
- package/src/modules/organization/query/listDepartmentsByCompany.ts +43 -0
- package/src/modules/organization/query/listSitesByCompany.generated.ts +5 -0
- package/src/modules/organization/query/listSitesByCompany.test.ts +126 -0
- package/src/modules/organization/query/listSitesByCompany.ts +41 -0
- package/src/modules/organization/tailor.config.ts +13 -0
- package/src/modules/organization/tailor.d.ts +13 -0
- package/src/modules/organization/testing/fixtures.ts +155 -0
- package/src/modules/primitives/README.md +1 -1
- package/src/modules/primitives/command/setBaseCurrency.test.ts +8 -64
- package/src/modules/primitives/command/setBaseCurrency.ts +6 -64
- package/src/modules/primitives/docs/commands/ActivateCategory.md +1 -1
- package/src/modules/primitives/docs/commands/ActivateCurrency.md +1 -1
- package/src/modules/primitives/docs/commands/ActivateUnit.md +1 -1
- package/src/modules/primitives/docs/commands/CreateExchangeRate.md +2 -2
- package/src/modules/primitives/docs/commands/CreateUnit.md +1 -1
- package/src/modules/primitives/docs/commands/DeactivateCategory.md +1 -1
- package/src/modules/primitives/docs/commands/DeactivateCurrency.md +1 -1
- package/src/modules/primitives/docs/commands/DeactivateUnit.md +1 -1
- package/src/modules/primitives/docs/commands/SetBaseCurrency.md +13 -23
- package/src/modules/primitives/docs/commands/SetReferenceUnit.md +1 -1
- package/src/modules/primitives/docs/features/currency-definitions.md +13 -14
- package/src/modules/primitives/docs/models/Currency.md +3 -4
- package/src/modules/primitives/docs/queries/ConvertAmount.md +2 -2
- package/src/modules/primitives/docs/queries/ConvertQuantity.md +2 -2
- package/src/modules/primitives/lib/errors.generated.ts +5 -0
- package/src/modules/product-management/README.md +1 -1
- package/src/modules/user-management/docs/commands/CreatePermission.md +3 -3
- package/src/modules/user-management/docs/commands/CreateRole.md +1 -1
- package/src/modules/user-management/docs/queries/ListRolePermissionsByRole.md +39 -0
- package/src/modules/user-management/docs/queries/ListUserRolesByUser.md +39 -0
- package/src/modules/user-management/generated/enums.ts +0 -15
- package/src/modules/user-management/generated/kysely-tailordb.ts +0 -11
- package/src/shared/createContext.ts +2 -1
- package/src/shared/defineQuery.ts +36 -1
- package/src/shared/requirePermission.ts +3 -3
- package/src/shared/types.ts +3 -0
- package/templates/scaffold/app/backend/package.json +8 -7
- package/templates/scaffold/app/frontend/eslint.config.js +12 -0
- package/templates/scaffold/app/frontend/package.json +19 -16
- package/templates/scaffold/app/frontend/src/hooks/use-toast.ts +30 -0
- package/templates/scaffold/app/frontend/src/pages/user-management/user/create/components/create-user-form.tsx +3 -2
- package/templates/scaffold/app/frontend/vite.config.ts +5 -5
- package/templates/workflows/erp-kit-check.yml +2 -2
- package/src/commands/module/list.test.ts +0 -57
- package/src/commands/module/list.ts +0 -64
- package/src/commands/scaffold.ts +0 -176
- /package/src/modules/{accounting → audit/db}/.gitkeep +0 -0
- /package/src/modules/audit/{.gitkeep → executor/.gitkeep} +0 -0
- /package/src/modules/{coa-management/.gitkeep → audit/lib/errors.ts} +0 -0
- /package/src/modules/{supplier-management → business-partner}/.gitkeep +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -362,22 +362,85 @@ const ALL_SCHEMAS = {
|
|
|
362
362
|
...APP_COMPOSE_SCHEMAS
|
|
363
363
|
};
|
|
364
364
|
//#endregion
|
|
365
|
-
//#region src/commands/
|
|
365
|
+
//#region src/commands/lib/paths.ts
|
|
366
|
+
const MODULE_PATHS = {
|
|
367
|
+
commands: "command",
|
|
368
|
+
db: "db",
|
|
369
|
+
queries: "query",
|
|
370
|
+
docs: {
|
|
371
|
+
commands: "docs/commands",
|
|
372
|
+
models: "docs/models",
|
|
373
|
+
queries: "docs/queries",
|
|
374
|
+
features: "docs/features"
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
const APP_PATHS = {
|
|
378
|
+
storySegment: "story",
|
|
379
|
+
docs: {
|
|
380
|
+
resolver: "docs/resolver",
|
|
381
|
+
actors: "docs/actors",
|
|
382
|
+
businessFlow: "docs/business-flow",
|
|
383
|
+
screen: "docs/screen"
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
//#endregion
|
|
387
|
+
//#region src/commands/lib/discovery.ts
|
|
388
|
+
function moduleCategories(root) {
|
|
389
|
+
return [
|
|
390
|
+
{
|
|
391
|
+
name: "command",
|
|
392
|
+
sourcePattern: `${root}/*/${MODULE_PATHS.commands}/*.ts`,
|
|
393
|
+
docPattern: `${root}/*/${MODULE_PATHS.docs.commands}/*.md`,
|
|
394
|
+
exclusions: [/\.test\.ts$/, /\.generated\.ts$/]
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
name: "model",
|
|
398
|
+
sourcePattern: `${root}/*/${MODULE_PATHS.db}/*.ts`,
|
|
399
|
+
docPattern: `${root}/*/${MODULE_PATHS.docs.models}/*.md`,
|
|
400
|
+
exclusions: [/\.test\.ts$/, /^index\.ts$/]
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
name: "query",
|
|
404
|
+
sourcePattern: `${root}/*/${MODULE_PATHS.queries}/*.ts`,
|
|
405
|
+
docPattern: `${root}/*/${MODULE_PATHS.docs.queries}/*.md`,
|
|
406
|
+
exclusions: [/\.test\.ts$/]
|
|
407
|
+
}
|
|
408
|
+
];
|
|
409
|
+
}
|
|
410
|
+
function appComposeCategories(root) {
|
|
411
|
+
return [{
|
|
412
|
+
name: "resolver",
|
|
413
|
+
sourcePattern: `${root}/*/backend/src/resolvers/*.ts`,
|
|
414
|
+
docPattern: `${root}/*/${APP_PATHS.docs.resolver}/*.md`,
|
|
415
|
+
exclusions: [/\.test\.ts$/, /^index\.ts$/]
|
|
416
|
+
}];
|
|
417
|
+
}
|
|
418
|
+
function testCaseCategories(root) {
|
|
419
|
+
return [{
|
|
420
|
+
name: "command-test-case",
|
|
421
|
+
docPattern: `${root}/*/${MODULE_PATHS.docs.commands}/*.md`,
|
|
422
|
+
testDir: MODULE_PATHS.commands
|
|
423
|
+
}, {
|
|
424
|
+
name: "query-test-case",
|
|
425
|
+
docPattern: `${root}/*/${MODULE_PATHS.docs.queries}/*.md`,
|
|
426
|
+
testDir: MODULE_PATHS.queries
|
|
427
|
+
}];
|
|
428
|
+
}
|
|
366
429
|
function buildCheckTargets(config) {
|
|
367
430
|
const targets = [];
|
|
368
431
|
if (config.modulesRoot) {
|
|
369
432
|
const m = config.modulesRoot;
|
|
370
433
|
targets.push({
|
|
371
|
-
glob: `${m}/[a-zA-Z]
|
|
434
|
+
glob: `${m}/[a-zA-Z]*/${MODULE_PATHS.docs.features}/*.md`,
|
|
372
435
|
schemaKey: "feature"
|
|
373
436
|
}, {
|
|
374
|
-
glob: `${m}/[a-zA-Z]
|
|
437
|
+
glob: `${m}/[a-zA-Z]*/${MODULE_PATHS.docs.commands}/*.md`,
|
|
375
438
|
schemaKey: "command"
|
|
376
439
|
}, {
|
|
377
|
-
glob: `${m}/[a-zA-Z]
|
|
440
|
+
glob: `${m}/[a-zA-Z]*/${MODULE_PATHS.docs.models}/*.md`,
|
|
378
441
|
schemaKey: "model"
|
|
379
442
|
}, {
|
|
380
|
-
glob: `${m}/[a-zA-Z]
|
|
443
|
+
glob: `${m}/[a-zA-Z]*/${MODULE_PATHS.docs.queries}/*.md`,
|
|
381
444
|
schemaKey: "query"
|
|
382
445
|
}, {
|
|
383
446
|
glob: `${m}/[a-zA-Z]*/README.md`,
|
|
@@ -390,24 +453,26 @@ function buildCheckTargets(config) {
|
|
|
390
453
|
glob: `${a}/[a-zA-Z]*/README.md`,
|
|
391
454
|
schemaKey: "app"
|
|
392
455
|
}, {
|
|
393
|
-
glob: `${a}/[a-zA-Z]
|
|
456
|
+
glob: `${a}/[a-zA-Z]*/${APP_PATHS.docs.actors}/*.md`,
|
|
394
457
|
schemaKey: "actors"
|
|
395
458
|
}, {
|
|
396
|
-
glob: `${a}/[a-zA-Z]
|
|
459
|
+
glob: `${a}/[a-zA-Z]*/${APP_PATHS.docs.businessFlow}/*/README.md`,
|
|
397
460
|
schemaKey: "business-flow"
|
|
398
461
|
}, {
|
|
399
|
-
glob: `${a}/[a-zA-Z]
|
|
462
|
+
glob: `${a}/[a-zA-Z]*/${APP_PATHS.docs.businessFlow}/*/${APP_PATHS.storySegment}/*.md`,
|
|
400
463
|
schemaKey: "story"
|
|
401
464
|
}, {
|
|
402
|
-
glob: `${a}/[a-zA-Z]
|
|
465
|
+
glob: `${a}/[a-zA-Z]*/${APP_PATHS.docs.screen}/*.md`,
|
|
403
466
|
schemaKey: "screen"
|
|
404
467
|
}, {
|
|
405
|
-
glob: `${a}/[a-zA-Z]
|
|
468
|
+
glob: `${a}/[a-zA-Z]*/${APP_PATHS.docs.resolver}/*.md`,
|
|
406
469
|
schemaKey: "resolver"
|
|
407
470
|
});
|
|
408
471
|
}
|
|
409
472
|
return targets;
|
|
410
473
|
}
|
|
474
|
+
//#endregion
|
|
475
|
+
//#region src/commands/check.ts
|
|
411
476
|
async function runCheck(config, cwd) {
|
|
412
477
|
const targets = buildCheckTargets(config);
|
|
413
478
|
const results = await Promise.all(targets.map(async (target) => {
|
|
@@ -430,83 +495,85 @@ async function runCheck(config, cwd) {
|
|
|
430
495
|
return results.some((code) => code !== 0) ? 1 : 0;
|
|
431
496
|
}
|
|
432
497
|
//#endregion
|
|
433
|
-
//#region src/commands/
|
|
434
|
-
function
|
|
435
|
-
|
|
498
|
+
//#region src/commands/init-module.ts
|
|
499
|
+
function runInitModule(name, dir) {
|
|
500
|
+
const moduleDir = path.resolve(dir, name);
|
|
501
|
+
if (fs.existsSync(moduleDir)) {
|
|
502
|
+
console.error(`Directory already exists: ${moduleDir}`);
|
|
503
|
+
return 1;
|
|
504
|
+
}
|
|
505
|
+
fs.mkdirSync(moduleDir, { recursive: true });
|
|
506
|
+
return 0;
|
|
436
507
|
}
|
|
437
|
-
function
|
|
438
|
-
|
|
508
|
+
async function runInitModuleWithReadme(name, dir, cwd) {
|
|
509
|
+
const initResult = runInitModule(name, dir);
|
|
510
|
+
if (initResult !== 0) return initResult;
|
|
511
|
+
const moduleDir = path.resolve(cwd, dir, name);
|
|
512
|
+
const readmePath = path.join(moduleDir, "README.md");
|
|
513
|
+
const schemaPath = MODULE_SCHEMAS.module;
|
|
514
|
+
const { exitCode, stdout, stderr } = await runMdschema([
|
|
515
|
+
"generate",
|
|
516
|
+
"--schema",
|
|
517
|
+
schemaPath,
|
|
518
|
+
"--output",
|
|
519
|
+
readmePath
|
|
520
|
+
], cwd);
|
|
521
|
+
if (stdout.trim()) console.log(stdout);
|
|
522
|
+
if (stderr.trim()) console.error(stderr);
|
|
523
|
+
return exitCode;
|
|
439
524
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
const tree = fromMarkdown(markdown);
|
|
446
|
-
const cases = [];
|
|
447
|
-
let collecting = false;
|
|
448
|
-
for (const node of tree.children) {
|
|
449
|
-
if (isHeading$1(node)) {
|
|
450
|
-
if (collecting) break;
|
|
451
|
-
if (node.depth === 2 && toString(node) === "Test Cases") {
|
|
452
|
-
collecting = true;
|
|
453
|
-
continue;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
if (collecting && isList$1(node)) for (const item of node.children) {
|
|
457
|
-
const text = toString(item).trim();
|
|
458
|
-
if (text) cases.push(text);
|
|
459
|
-
}
|
|
525
|
+
function runInitApp(name, dir) {
|
|
526
|
+
const appDir = path.resolve(dir, name);
|
|
527
|
+
if (fs.existsSync(appDir)) {
|
|
528
|
+
console.error(`Directory already exists: ${appDir}`);
|
|
529
|
+
return 1;
|
|
460
530
|
}
|
|
461
|
-
|
|
531
|
+
fs.mkdirSync(appDir, { recursive: true });
|
|
532
|
+
return 0;
|
|
462
533
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
const
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
534
|
+
async function runInitAppWithReadme(name, dir, cwd) {
|
|
535
|
+
const initResult = runInitApp(name, dir);
|
|
536
|
+
if (initResult !== 0) return initResult;
|
|
537
|
+
const appDir = path.resolve(cwd, dir, name);
|
|
538
|
+
const readmePath = path.join(appDir, "README.md");
|
|
539
|
+
const schemaPath = APP_COMPOSE_SCHEMAS.app;
|
|
540
|
+
const { exitCode, stdout, stderr } = await runMdschema([
|
|
541
|
+
"generate",
|
|
542
|
+
"--schema",
|
|
543
|
+
schemaPath,
|
|
544
|
+
"--output",
|
|
545
|
+
readmePath
|
|
546
|
+
], cwd);
|
|
547
|
+
if (stdout.trim()) console.log(stdout);
|
|
548
|
+
if (stderr.trim()) console.error(stderr);
|
|
549
|
+
return exitCode;
|
|
473
550
|
}
|
|
474
551
|
//#endregion
|
|
475
|
-
//#region src/commands/
|
|
476
|
-
function
|
|
477
|
-
return
|
|
478
|
-
{
|
|
479
|
-
name: "command",
|
|
480
|
-
sourcePattern: `${root}/*/command/*.ts`,
|
|
481
|
-
docPattern: `${root}/*/docs/commands/*.md`,
|
|
482
|
-
exclusions: [/\.test\.ts$/, /\.generated\.ts$/]
|
|
483
|
-
},
|
|
484
|
-
{
|
|
485
|
-
name: "model",
|
|
486
|
-
sourcePattern: `${root}/*/db/*.ts`,
|
|
487
|
-
docPattern: `${root}/*/docs/models/*.md`,
|
|
488
|
-
exclusions: [/\.test\.ts$/, /^index\.ts$/]
|
|
489
|
-
},
|
|
490
|
-
{
|
|
491
|
-
name: "query",
|
|
492
|
-
sourcePattern: `${root}/*/query/*.ts`,
|
|
493
|
-
docPattern: `${root}/*/docs/queries/*.md`,
|
|
494
|
-
exclusions: [/\.test\.ts$/]
|
|
495
|
-
}
|
|
496
|
-
];
|
|
552
|
+
//#region src/commands/lib/command-result.ts
|
|
553
|
+
function success() {
|
|
554
|
+
return { exitCode: 0 };
|
|
497
555
|
}
|
|
498
|
-
function
|
|
499
|
-
return
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
556
|
+
function silentFailure(exitCode = 1) {
|
|
557
|
+
return {
|
|
558
|
+
exitCode,
|
|
559
|
+
message: ""
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
async function runCommand(fn) {
|
|
563
|
+
const result = await fn();
|
|
564
|
+
if (result.exitCode !== 0 && "message" in result && result.message) console.error(result.message);
|
|
565
|
+
return result;
|
|
505
566
|
}
|
|
567
|
+
async function executeCommand(fn) {
|
|
568
|
+
const result = await runCommand(fn);
|
|
569
|
+
process.exit(result.exitCode);
|
|
570
|
+
}
|
|
571
|
+
//#endregion
|
|
572
|
+
//#region src/commands/lib/sync-check-source.ts
|
|
506
573
|
function shouldExclude(fileName, exclusions) {
|
|
507
574
|
return exclusions.some((pattern) => pattern.test(fileName));
|
|
508
575
|
}
|
|
509
|
-
async function
|
|
576
|
+
async function runSourceSyncCheck(config, cwd) {
|
|
510
577
|
const errors = [];
|
|
511
578
|
let totalSources = 0;
|
|
512
579
|
let totalDocs = 0;
|
|
@@ -543,10 +610,6 @@ async function runSyncCheck(config, cwd) {
|
|
|
543
610
|
totalSources += sourceBasenames.size;
|
|
544
611
|
totalDocs += docBasenames.size;
|
|
545
612
|
}
|
|
546
|
-
if (config.modulesRoot) {
|
|
547
|
-
const testCaseErrors = await runTestCaseSyncCheck(config.modulesRoot, cwd);
|
|
548
|
-
errors.push(...testCaseErrors);
|
|
549
|
-
}
|
|
550
613
|
return {
|
|
551
614
|
exitCode: errors.length > 0 ? 1 : 0,
|
|
552
615
|
errors,
|
|
@@ -557,17 +620,56 @@ async function runSyncCheck(config, cwd) {
|
|
|
557
620
|
}
|
|
558
621
|
};
|
|
559
622
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
623
|
+
//#endregion
|
|
624
|
+
//#region src/commands/parse-doc-test-cases.ts
|
|
625
|
+
function isHeading$2(node) {
|
|
626
|
+
return node.type === "heading";
|
|
627
|
+
}
|
|
628
|
+
function isList$1(node) {
|
|
629
|
+
return node.type === "list";
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Parse test case descriptions from the `## Test Cases` section of a Markdown doc.
|
|
633
|
+
* Uses mdast to traverse the AST instead of string matching.
|
|
634
|
+
*/
|
|
635
|
+
function parseTestCasesFromDoc(markdown) {
|
|
636
|
+
const tree = fromMarkdown(markdown);
|
|
637
|
+
const cases = [];
|
|
638
|
+
let collecting = false;
|
|
639
|
+
for (const node of tree.children) {
|
|
640
|
+
if (isHeading$2(node)) {
|
|
641
|
+
if (collecting) break;
|
|
642
|
+
if (node.depth === 2 && toString(node) === "Test Cases") {
|
|
643
|
+
collecting = true;
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
if (collecting && isList$1(node)) for (const item of node.children) {
|
|
648
|
+
const text = toString(item).trim();
|
|
649
|
+
if (text) cases.push(text);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
return cases;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Parse `it("...")` descriptions from a test file using regex.
|
|
656
|
+
* Test files are not Markdown, so regex is appropriate here.
|
|
657
|
+
* Uses separate patterns per quote type so that e.g. an apostrophe
|
|
658
|
+
* inside a double-quoted string does not end the match early.
|
|
659
|
+
*/
|
|
660
|
+
function parseItDescriptionsFromTest(content) {
|
|
661
|
+
const descriptions = [];
|
|
662
|
+
const regex = /\bit\(\s*"([^"]+)"/gs;
|
|
663
|
+
let match;
|
|
664
|
+
while ((match = regex.exec(content)) !== null) descriptions.push(match[1].replace(/\s+/g, " ").trim());
|
|
665
|
+
const singleQuoteRegex = /\bit\(\s*'([^']+)'/gs;
|
|
666
|
+
while ((match = singleQuoteRegex.exec(content)) !== null) descriptions.push(match[1].replace(/\s+/g, " ").trim());
|
|
667
|
+
const backtickRegex = /\bit\(\s*`([^`]+)`/gs;
|
|
668
|
+
while ((match = backtickRegex.exec(content)) !== null) descriptions.push(match[1].replace(/\s+/g, " ").trim());
|
|
669
|
+
return descriptions;
|
|
570
670
|
}
|
|
671
|
+
//#endregion
|
|
672
|
+
//#region src/commands/lib/sync-check-tests.ts
|
|
571
673
|
function toCamelCase(pascalCase) {
|
|
572
674
|
return pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1);
|
|
573
675
|
}
|
|
@@ -609,6 +711,17 @@ async function runTestCaseSyncCheck(root, cwd) {
|
|
|
609
711
|
}
|
|
610
712
|
return errors;
|
|
611
713
|
}
|
|
714
|
+
//#endregion
|
|
715
|
+
//#region src/commands/sync-check.ts
|
|
716
|
+
async function runSyncCheck(config, cwd) {
|
|
717
|
+
const sourceResult = await runSourceSyncCheck(config, cwd);
|
|
718
|
+
if (config.modulesRoot) {
|
|
719
|
+
const testCaseErrors = await runTestCaseSyncCheck(config.modulesRoot, cwd);
|
|
720
|
+
sourceResult.errors.push(...testCaseErrors);
|
|
721
|
+
sourceResult.exitCode = sourceResult.errors.length > 0 ? 1 : 0;
|
|
722
|
+
}
|
|
723
|
+
return sourceResult;
|
|
724
|
+
}
|
|
612
725
|
function formatSyncCheckReport(result) {
|
|
613
726
|
const lines = [];
|
|
614
727
|
lines.push(chalk.bold("docs-sync-check: Checking source-documentation correspondence...\n"));
|
|
@@ -655,158 +768,6 @@ function formatSyncCheckReport(result) {
|
|
|
655
768
|
return lines.join("\n");
|
|
656
769
|
}
|
|
657
770
|
//#endregion
|
|
658
|
-
//#region src/commands/scaffold.ts
|
|
659
|
-
const MODULE_TYPES = [
|
|
660
|
-
"module",
|
|
661
|
-
"feature",
|
|
662
|
-
"command",
|
|
663
|
-
"model",
|
|
664
|
-
"query"
|
|
665
|
-
];
|
|
666
|
-
const APP_TYPES = [
|
|
667
|
-
"app",
|
|
668
|
-
"actors",
|
|
669
|
-
"business-flow",
|
|
670
|
-
"story",
|
|
671
|
-
"screen",
|
|
672
|
-
"resolver"
|
|
673
|
-
];
|
|
674
|
-
[...MODULE_TYPES, ...APP_TYPES];
|
|
675
|
-
const MODULE_DIR_MAP = {
|
|
676
|
-
feature: "docs/features",
|
|
677
|
-
command: "docs/commands",
|
|
678
|
-
model: "docs/models",
|
|
679
|
-
query: "docs/queries"
|
|
680
|
-
};
|
|
681
|
-
const APP_DIR_MAP = {
|
|
682
|
-
actors: "docs/actors",
|
|
683
|
-
"business-flow": "docs/business-flow",
|
|
684
|
-
screen: "docs/screen",
|
|
685
|
-
resolver: "docs/resolver"
|
|
686
|
-
};
|
|
687
|
-
function resolveScaffoldPath(type, parentName, name, root) {
|
|
688
|
-
if (type === "module" || type === "app") return path.join(root, parentName, "README.md");
|
|
689
|
-
if (!name) throw new Error(`Name is required for scaffold type "${type}"`);
|
|
690
|
-
if (type === "business-flow") return path.join(root, parentName, "docs/business-flow", name, "README.md");
|
|
691
|
-
if (type === "story") {
|
|
692
|
-
const parts = name.split("/");
|
|
693
|
-
if (parts.length !== 2) throw new Error(`Story name must be "<flow>/<story>" (e.g., "onboarding/admin--create-user")`);
|
|
694
|
-
return path.join(root, parentName, "docs/business-flow", parts[0], "story", `${parts[1]}.md`);
|
|
695
|
-
}
|
|
696
|
-
if (MODULE_DIR_MAP[type]) return path.join(root, parentName, MODULE_DIR_MAP[type], `${name}.md`);
|
|
697
|
-
if (APP_DIR_MAP[type]) return path.join(root, parentName, APP_DIR_MAP[type], `${name}.md`);
|
|
698
|
-
throw new Error(`Unknown scaffold type: ${type}`);
|
|
699
|
-
}
|
|
700
|
-
async function runScaffold(type, parentName, name, root, cwd) {
|
|
701
|
-
const outputPath = resolveScaffoldPath(type, parentName, name, root);
|
|
702
|
-
const absoluteOutput = path.resolve(cwd, outputPath);
|
|
703
|
-
if (fs.existsSync(absoluteOutput)) {
|
|
704
|
-
console.error(`File already exists: ${outputPath}`);
|
|
705
|
-
return 1;
|
|
706
|
-
}
|
|
707
|
-
const schemaPath = ALL_SCHEMAS[type];
|
|
708
|
-
if (!schemaPath) {
|
|
709
|
-
console.error(`No schema found for type: ${type}`);
|
|
710
|
-
return 2;
|
|
711
|
-
}
|
|
712
|
-
try {
|
|
713
|
-
fs.mkdirSync(path.dirname(absoluteOutput), { recursive: true });
|
|
714
|
-
} catch (err) {
|
|
715
|
-
console.error(`Failed to create directory: ${err instanceof Error ? err.message : String(err)}`);
|
|
716
|
-
return 1;
|
|
717
|
-
}
|
|
718
|
-
const { exitCode, stdout, stderr } = await runMdschema([
|
|
719
|
-
"generate",
|
|
720
|
-
"--schema",
|
|
721
|
-
schemaPath,
|
|
722
|
-
"--output",
|
|
723
|
-
absoluteOutput
|
|
724
|
-
], cwd);
|
|
725
|
-
if (stdout.trim()) console.log(stdout);
|
|
726
|
-
if (stderr.trim()) console.error(stderr);
|
|
727
|
-
if (exitCode !== 0) return exitCode;
|
|
728
|
-
if (type === "module") scaffoldModuleSrc(path.dirname(absoluteOutput), parentName);
|
|
729
|
-
if (type === "app") scaffoldAppSrc(path.dirname(absoluteOutput), parentName);
|
|
730
|
-
return exitCode;
|
|
731
|
-
}
|
|
732
|
-
function copyTemplateDir(srcDir, destDir, replacements, placeholderFiles) {
|
|
733
|
-
for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
734
|
-
const srcPath = path.join(srcDir, entry.name);
|
|
735
|
-
const destName = entry.name === "__dot__gitignore" ? ".gitignore" : entry.name;
|
|
736
|
-
const destPath = path.join(destDir, destName);
|
|
737
|
-
if (entry.isDirectory()) {
|
|
738
|
-
fs.mkdirSync(destPath, { recursive: true });
|
|
739
|
-
copyTemplateDir(srcPath, destPath, replacements, placeholderFiles);
|
|
740
|
-
} else {
|
|
741
|
-
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
742
|
-
if (placeholderFiles.has(entry.name)) {
|
|
743
|
-
let content = fs.readFileSync(srcPath, "utf-8");
|
|
744
|
-
for (const [from, to] of Object.entries(replacements)) content = content.replaceAll(from, to);
|
|
745
|
-
fs.writeFileSync(destPath, content);
|
|
746
|
-
} else fs.copyFileSync(srcPath, destPath);
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
function scaffoldModuleSrc(moduleDir, moduleName) {
|
|
751
|
-
copyTemplateDir(path.join(PACKAGE_ROOT, "templates", "scaffold", "module"), moduleDir, { "template-module": moduleName }, new Set(["permissions.ts", "tailor.config.ts"]));
|
|
752
|
-
}
|
|
753
|
-
function scaffoldAppSrc(appDir, appName) {
|
|
754
|
-
const templateDir = path.join(PACKAGE_ROOT, "templates", "scaffold", "app");
|
|
755
|
-
const erpKitVersion = readErpKitVersion();
|
|
756
|
-
copyTemplateDir(templateDir, appDir, {
|
|
757
|
-
"template-app-frontend": `${appName}-frontend`,
|
|
758
|
-
"template-app-backend": appName,
|
|
759
|
-
"template-app": appName,
|
|
760
|
-
"\"workspace:*\"": `"${erpKitVersion}"`
|
|
761
|
-
}, new Set([
|
|
762
|
-
"package.json",
|
|
763
|
-
"tailor.config.ts",
|
|
764
|
-
"index.html"
|
|
765
|
-
]));
|
|
766
|
-
}
|
|
767
|
-
//#endregion
|
|
768
|
-
//#region src/commands/module/list.ts
|
|
769
|
-
const MODULES_DIR = join(PACKAGE_ROOT, "src", "modules");
|
|
770
|
-
const EXCLUDED_DIRS = new Set(["shared", "testing"]);
|
|
771
|
-
function countFiles(dir, pattern, exclusions) {
|
|
772
|
-
if (!existsSync(dir)) return 0;
|
|
773
|
-
return readdirSync(dir).filter((f) => pattern.test(f) && !exclusions.some((p) => p.test(f))).length;
|
|
774
|
-
}
|
|
775
|
-
function listModules() {
|
|
776
|
-
if (!existsSync(MODULES_DIR)) return [];
|
|
777
|
-
return readdirSync(MODULES_DIR, { withFileTypes: true }).filter((d) => d.isDirectory() && !EXCLUDED_DIRS.has(d.name)).map((d) => {
|
|
778
|
-
const modDir = join(MODULES_DIR, d.name);
|
|
779
|
-
return {
|
|
780
|
-
name: d.name,
|
|
781
|
-
commands: countFiles(join(modDir, "command"), /\.ts$/, [/\.test\.ts$/]),
|
|
782
|
-
models: countFiles(join(modDir, "db"), /\.ts$/, [/\.test\.ts$/, /^index\.ts$/]),
|
|
783
|
-
features: countFiles(join(modDir, "docs", "features"), /\.md$/, [])
|
|
784
|
-
};
|
|
785
|
-
}).sort((a, b) => a.name.localeCompare(b.name));
|
|
786
|
-
}
|
|
787
|
-
function formatModuleList(modules) {
|
|
788
|
-
if (modules.length === 0) return "No modules found.";
|
|
789
|
-
const lines = [];
|
|
790
|
-
lines.push(chalk.bold("Modules:\n"));
|
|
791
|
-
const nameWidth = Math.max(...modules.map((m) => m.name.length), 4);
|
|
792
|
-
for (const mod of modules) {
|
|
793
|
-
const counts = [
|
|
794
|
-
`${mod.commands} commands`,
|
|
795
|
-
`${mod.models} models`,
|
|
796
|
-
`${mod.features} features`
|
|
797
|
-
].join(", ");
|
|
798
|
-
lines.push(` ${mod.name.padEnd(nameWidth)} ${counts}`);
|
|
799
|
-
}
|
|
800
|
-
lines.push("");
|
|
801
|
-
lines.push(`${modules.length} modules`);
|
|
802
|
-
return lines.join("\n");
|
|
803
|
-
}
|
|
804
|
-
function runModuleList() {
|
|
805
|
-
const modules = listModules();
|
|
806
|
-
console.log(formatModuleList(modules));
|
|
807
|
-
return 0;
|
|
808
|
-
}
|
|
809
|
-
//#endregion
|
|
810
771
|
//#region src/generator/parse-command-doc.ts
|
|
811
772
|
function parseCommandDoc(fileName, markdown) {
|
|
812
773
|
const commandName = fileName.charAt(0).toLowerCase() + fileName.slice(1);
|
|
@@ -820,17 +781,17 @@ function parseCommandDoc(fileName, markdown) {
|
|
|
820
781
|
function errorCodeToClassName(code) {
|
|
821
782
|
return code.toLowerCase().split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("") + "Error";
|
|
822
783
|
}
|
|
823
|
-
function isHeading(node) {
|
|
784
|
+
function isHeading$1(node) {
|
|
824
785
|
return node.type === "heading";
|
|
825
786
|
}
|
|
826
787
|
function isList(node) {
|
|
827
788
|
return node.type === "list";
|
|
828
789
|
}
|
|
829
|
-
function getNodesUnderHeading(tree, headingText) {
|
|
790
|
+
function getNodesUnderHeading$1(tree, headingText) {
|
|
830
791
|
const nodes = [];
|
|
831
792
|
let collecting = false;
|
|
832
793
|
for (const node of tree.children) {
|
|
833
|
-
if (isHeading(node)) {
|
|
794
|
+
if (isHeading$1(node)) {
|
|
834
795
|
if (collecting) break;
|
|
835
796
|
if (node.depth === 2 && toString(node) === headingText) {
|
|
836
797
|
collecting = true;
|
|
@@ -843,7 +804,7 @@ function getNodesUnderHeading(tree, headingText) {
|
|
|
843
804
|
}
|
|
844
805
|
const ERROR_PATTERN = /^([A-Z_]+):\s*(.+)$/;
|
|
845
806
|
function parseErrorScenarios(tree) {
|
|
846
|
-
const nodes = getNodesUnderHeading(tree, "Error Scenarios");
|
|
807
|
+
const nodes = getNodesUnderHeading$1(tree, "Error Scenarios");
|
|
847
808
|
const errors = [];
|
|
848
809
|
for (const node of nodes) {
|
|
849
810
|
if (!isList(node)) continue;
|
|
@@ -860,7 +821,7 @@ function parseErrorScenarios(tree) {
|
|
|
860
821
|
}
|
|
861
822
|
const DEPENDENCY_PATTERN = /^([^:]+)::(.+)$/;
|
|
862
823
|
function parseExternalDependencies(tree) {
|
|
863
|
-
const nodes = getNodesUnderHeading(tree, "External Dependencies");
|
|
824
|
+
const nodes = getNodesUnderHeading$1(tree, "External Dependencies");
|
|
864
825
|
const deps = [];
|
|
865
826
|
for (const node of nodes) {
|
|
866
827
|
if (!isList(node)) continue;
|
|
@@ -880,7 +841,7 @@ function parseExternalDependencies(tree) {
|
|
|
880
841
|
return deps;
|
|
881
842
|
}
|
|
882
843
|
//#endregion
|
|
883
|
-
//#region src/generator/generate-
|
|
844
|
+
//#region src/generator/generate-errors.ts
|
|
884
845
|
function moduleNameToPrefix(moduleName) {
|
|
885
846
|
return moduleName.toUpperCase().replace(/-/g, "_");
|
|
886
847
|
}
|
|
@@ -906,9 +867,49 @@ import { createDomainError } from "../../../shared";
|
|
|
906
867
|
|
|
907
868
|
${lines.join("\n")}`;
|
|
908
869
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
870
|
+
//#endregion
|
|
871
|
+
//#region src/generator/generate-permissions.ts
|
|
872
|
+
function generatePermissions(moduleName, commandNames) {
|
|
873
|
+
return `// @generated — do not edit
|
|
874
|
+
import { definePermissions } from "../../../shared";
|
|
875
|
+
|
|
876
|
+
export const { permissions, own, all } = definePermissions("${moduleName}", [
|
|
877
|
+
${[...commandNames].sort().map((name) => ` "${name}",`).join("\n")}
|
|
878
|
+
] as const);
|
|
879
|
+
`;
|
|
880
|
+
}
|
|
881
|
+
//#endregion
|
|
882
|
+
//#region src/generator/generate-shells.ts
|
|
883
|
+
function generateCommandShell(doc) {
|
|
884
|
+
return [
|
|
885
|
+
`// @generated — do not edit`,
|
|
886
|
+
`import { defineCommand } from "../../../shared";`,
|
|
887
|
+
`import { permissions } from "../lib/permissions.generated";`,
|
|
888
|
+
`import { run } from "./${doc.commandName}";`,
|
|
889
|
+
``,
|
|
890
|
+
`export const ${doc.commandName} = defineCommand(permissions.${doc.commandName}, run);`,
|
|
891
|
+
``
|
|
892
|
+
].join("\n");
|
|
893
|
+
}
|
|
894
|
+
function generateQueryShell(doc) {
|
|
895
|
+
return [
|
|
896
|
+
`// @generated — do not edit`,
|
|
897
|
+
`import { defineQuery } from "../../../shared";`,
|
|
898
|
+
`import { run } from "./${doc.commandName}";`,
|
|
899
|
+
``,
|
|
900
|
+
`export const ${doc.commandName} = defineQuery(run);`,
|
|
901
|
+
``
|
|
902
|
+
].join("\n");
|
|
903
|
+
}
|
|
904
|
+
//#endregion
|
|
905
|
+
//#region src/generator/stub-templates.ts
|
|
906
|
+
function toPascal(name) {
|
|
907
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
908
|
+
}
|
|
909
|
+
const templates = {
|
|
910
|
+
command: { render: (name) => {
|
|
911
|
+
const inputType = `${toPascal(name)}Input`;
|
|
912
|
+
return `import { ok, type CommandContext } from "../../../shared";
|
|
912
913
|
import type { Transaction } from "../generated/kysely-tailordb";
|
|
913
914
|
|
|
914
915
|
export interface ${inputType} {
|
|
@@ -920,19 +921,19 @@ export async function run(db: Transaction, input: ${inputType}, ctx: CommandCont
|
|
|
920
921
|
return ok({});
|
|
921
922
|
}
|
|
922
923
|
`;
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
924
|
+
} },
|
|
925
|
+
commandTest: { render: (name) => {
|
|
926
|
+
const pascal = toPascal(name);
|
|
927
|
+
return `import { describe, expect, it } from "vitest";
|
|
927
928
|
import { createMockDb } from "../../../testing/index";
|
|
928
929
|
import type { CommandContext } from "../../../shared";
|
|
929
930
|
import type { Transaction } from "../generated/kysely-tailordb";
|
|
930
|
-
import { run, ${pascal}Input } from "./${
|
|
931
|
+
import { run, ${pascal}Input } from "./${name}";
|
|
931
932
|
|
|
932
|
-
describe("${
|
|
933
|
+
describe("${name} - test scenario", () => {
|
|
933
934
|
const ctx: CommandContext = {
|
|
934
935
|
actorId: "test-actor",
|
|
935
|
-
permissions: ["TODO:${
|
|
936
|
+
permissions: ["TODO:${name}"],
|
|
936
937
|
};
|
|
937
938
|
|
|
938
939
|
it("should be implemented", async () => {
|
|
@@ -942,31 +943,10 @@ describe("${doc.commandName} - test scenario", () => {
|
|
|
942
943
|
});
|
|
943
944
|
});
|
|
944
945
|
`;
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
`import { defineCommand } from "../../../shared";`,
|
|
950
|
-
`import { permissions } from "../lib/permissions.generated";`,
|
|
951
|
-
`import { run } from "./${doc.commandName}";`,
|
|
952
|
-
``,
|
|
953
|
-
`export const ${doc.commandName} = defineCommand(permissions.${doc.commandName}, run);`,
|
|
954
|
-
``
|
|
955
|
-
].join("\n");
|
|
956
|
-
}
|
|
957
|
-
function generateQueryShell(doc) {
|
|
958
|
-
return [
|
|
959
|
-
`// @generated — do not edit`,
|
|
960
|
-
`import { defineQuery } from "../../../shared";`,
|
|
961
|
-
`import { run } from "./${doc.commandName}";`,
|
|
962
|
-
``,
|
|
963
|
-
`export const ${doc.commandName} = defineQuery(run);`,
|
|
964
|
-
``
|
|
965
|
-
].join("\n");
|
|
966
|
-
}
|
|
967
|
-
function generateQueryStub(doc) {
|
|
968
|
-
const inputType = `${doc.commandName.charAt(0).toUpperCase() + doc.commandName.slice(1)}Input`;
|
|
969
|
-
return `import type { ReadonlyDB } from "../../../shared";
|
|
946
|
+
} },
|
|
947
|
+
query: { render: (name) => {
|
|
948
|
+
const inputType = `${toPascal(name)}Input`;
|
|
949
|
+
return `import type { ReadonlyDB } from "../../../shared";
|
|
970
950
|
import type { DB } from "../generated/kysely-tailordb";
|
|
971
951
|
|
|
972
952
|
export interface ${inputType} {
|
|
@@ -978,15 +958,15 @@ export async function run(db: ReadonlyDB<DB>, input: ${inputType}) {
|
|
|
978
958
|
return {};
|
|
979
959
|
}
|
|
980
960
|
`;
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
961
|
+
} },
|
|
962
|
+
queryTest: { render: (name) => {
|
|
963
|
+
const inputType = `${toPascal(name)}Input`;
|
|
964
|
+
return `import { describe, expect, it } from "vitest";
|
|
985
965
|
import { createMockDb } from "../../../testing/index";
|
|
986
966
|
import type { DB } from "../generated/kysely-tailordb";
|
|
987
|
-
import { run, type ${inputType} } from "./${
|
|
967
|
+
import { run, type ${inputType} } from "./${name}";
|
|
988
968
|
|
|
989
|
-
describe("${
|
|
969
|
+
describe("${name}", () => {
|
|
990
970
|
it("should be implemented", async () => {
|
|
991
971
|
const { db } = createMockDb<DB>();
|
|
992
972
|
const result = await run(db, {} as ${inputType});
|
|
@@ -994,28 +974,140 @@ describe("${doc.commandName}", () => {
|
|
|
994
974
|
});
|
|
995
975
|
});
|
|
996
976
|
`;
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
import { definePermissions } from "../../../shared";
|
|
977
|
+
} },
|
|
978
|
+
db: { render: (name) => {
|
|
979
|
+
return `import { db, unsafeAllowAllGqlPermission, unsafeAllowAllTypePermission } from "@tailor-platform/sdk";
|
|
1001
980
|
|
|
1002
|
-
export const {
|
|
1003
|
-
|
|
1004
|
-
|
|
981
|
+
export const ${name} = db
|
|
982
|
+
.type("${toPascal(name)}", {
|
|
983
|
+
// TODO: define fields
|
|
984
|
+
...db.fields.timestamps(),
|
|
985
|
+
})
|
|
986
|
+
.permission(unsafeAllowAllTypePermission)
|
|
987
|
+
.gqlPermission(unsafeAllowAllGqlPermission);
|
|
988
|
+
`;
|
|
989
|
+
} },
|
|
990
|
+
resolver: { render: (name) => {
|
|
991
|
+
return `import { createResolver, t } from "@tailor-platform/sdk";
|
|
992
|
+
import { createContext } from "@tailor-platform/erp-kit/app";
|
|
993
|
+
import { getDB } from "@/generated/kysely-tailordb";
|
|
994
|
+
|
|
995
|
+
export default createResolver({
|
|
996
|
+
name: "${name}",
|
|
997
|
+
operation: "mutation",
|
|
998
|
+
input: {
|
|
999
|
+
// TODO: define input fields
|
|
1000
|
+
},
|
|
1001
|
+
body: async (context) => {
|
|
1002
|
+
const db = getDB("main-db");
|
|
1003
|
+
return db.transaction().execute(async (trx) => {
|
|
1004
|
+
// TODO: implement
|
|
1005
|
+
return {};
|
|
1006
|
+
});
|
|
1007
|
+
},
|
|
1008
|
+
output: t
|
|
1009
|
+
.object({
|
|
1010
|
+
// TODO: define output fields
|
|
1011
|
+
})
|
|
1012
|
+
.description("${toPascal(name)} response"),
|
|
1013
|
+
});
|
|
1014
|
+
`;
|
|
1015
|
+
} },
|
|
1016
|
+
resolverTest: { render: (name) => {
|
|
1017
|
+
return `import { describe, expect, it } from "vitest";
|
|
1018
|
+
|
|
1019
|
+
describe("${name}", () => {
|
|
1020
|
+
it("should be implemented", async () => {
|
|
1021
|
+
const resolver = await import("./${name}");
|
|
1022
|
+
expect(resolver.default).toBeDefined();
|
|
1023
|
+
expect(resolver.default.name).toBe("${name}");
|
|
1024
|
+
});
|
|
1025
|
+
});
|
|
1005
1026
|
`;
|
|
1027
|
+
} }
|
|
1028
|
+
};
|
|
1029
|
+
function renderStub(type, name) {
|
|
1030
|
+
return templates[type].render(name);
|
|
1031
|
+
}
|
|
1032
|
+
//#endregion
|
|
1033
|
+
//#region src/generator/generate-stubs.ts
|
|
1034
|
+
function generateCommandStub(doc) {
|
|
1035
|
+
return renderStub("command", doc.commandName);
|
|
1036
|
+
}
|
|
1037
|
+
function generateTestStub(doc) {
|
|
1038
|
+
return renderStub("commandTest", doc.commandName);
|
|
1039
|
+
}
|
|
1040
|
+
function generateQueryStub(doc) {
|
|
1041
|
+
return renderStub("query", doc.commandName);
|
|
1042
|
+
}
|
|
1043
|
+
function generateQueryTestStub(doc) {
|
|
1044
|
+
return renderStub("queryTest", doc.commandName);
|
|
1045
|
+
}
|
|
1046
|
+
function generateDbStub(modelName) {
|
|
1047
|
+
return renderStub("db", modelName);
|
|
1006
1048
|
}
|
|
1049
|
+
function generateResolverStub(resolverName) {
|
|
1050
|
+
return renderStub("resolver", resolverName);
|
|
1051
|
+
}
|
|
1052
|
+
function generateResolverTestStub(resolverName) {
|
|
1053
|
+
return renderStub("resolverTest", resolverName);
|
|
1054
|
+
}
|
|
1055
|
+
//#endregion
|
|
1056
|
+
//#region src/generator/scaffold.ts
|
|
1057
|
+
function copyTemplateDir(srcDir, destDir, replacements, placeholderFiles) {
|
|
1058
|
+
for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
1059
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
1060
|
+
const destName = entry.name === "__dot__gitignore" ? ".gitignore" : entry.name;
|
|
1061
|
+
const destPath = path.join(destDir, destName);
|
|
1062
|
+
if (entry.name === "node_modules") continue;
|
|
1063
|
+
if (entry.isDirectory()) {
|
|
1064
|
+
fs.mkdirSync(destPath, { recursive: true });
|
|
1065
|
+
copyTemplateDir(srcPath, destPath, replacements, placeholderFiles);
|
|
1066
|
+
} else {
|
|
1067
|
+
if (fs.existsSync(destPath)) continue;
|
|
1068
|
+
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
1069
|
+
if (placeholderFiles.has(entry.name)) {
|
|
1070
|
+
let content = fs.readFileSync(srcPath, "utf-8");
|
|
1071
|
+
for (const [from, to] of Object.entries(replacements)) content = content.replaceAll(from, to);
|
|
1072
|
+
fs.writeFileSync(destPath, content);
|
|
1073
|
+
} else fs.copyFileSync(srcPath, destPath);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
function scaffoldModuleBoilerplate(moduleDir, moduleName) {
|
|
1078
|
+
copyTemplateDir(path.join(PACKAGE_ROOT, "templates", "scaffold", "module"), moduleDir, { "template-module": moduleName }, new Set(["permissions.ts", "tailor.config.ts"]));
|
|
1079
|
+
}
|
|
1080
|
+
function scaffoldAppBoilerplate(appDir, appName) {
|
|
1081
|
+
const templateDir = path.join(PACKAGE_ROOT, "templates", "scaffold", "app");
|
|
1082
|
+
const erpKitVersion = readErpKitVersion();
|
|
1083
|
+
copyTemplateDir(templateDir, appDir, {
|
|
1084
|
+
"template-app-frontend": `${appName}-frontend`,
|
|
1085
|
+
"template-app-backend": appName,
|
|
1086
|
+
"template-app": appName,
|
|
1087
|
+
"\"workspace:*\"": `"${erpKitVersion}"`
|
|
1088
|
+
}, new Set([
|
|
1089
|
+
"package.json",
|
|
1090
|
+
"tailor.config.ts",
|
|
1091
|
+
"index.html"
|
|
1092
|
+
]));
|
|
1093
|
+
}
|
|
1094
|
+
//#endregion
|
|
1095
|
+
//#region src/generator/generate-code.ts
|
|
1007
1096
|
function runGenerateCode(modulePath, moduleName) {
|
|
1097
|
+
scaffoldModuleBoilerplate(modulePath, moduleName);
|
|
1008
1098
|
const docsDir = path.join(modulePath, "docs", "commands");
|
|
1009
1099
|
const libDir = path.join(modulePath, "lib");
|
|
1010
1100
|
const commandDir = path.join(modulePath, "command");
|
|
1011
1101
|
if (!fs.existsSync(docsDir)) {
|
|
1012
|
-
console.
|
|
1013
|
-
|
|
1102
|
+
console.log(`No docs/commands/ directory found — skipping code generation`);
|
|
1103
|
+
console.log(`Generated boilerplate for ${moduleName}`);
|
|
1104
|
+
return 0;
|
|
1014
1105
|
}
|
|
1015
1106
|
const mdFiles = fs.readdirSync(docsDir).filter((f) => f.endsWith(".md"));
|
|
1016
1107
|
if (mdFiles.length === 0) {
|
|
1017
|
-
console.
|
|
1018
|
-
|
|
1108
|
+
console.log(`No command docs found — skipping code generation`);
|
|
1109
|
+
console.log(`Generated boilerplate for ${moduleName}`);
|
|
1110
|
+
return 0;
|
|
1019
1111
|
}
|
|
1020
1112
|
const parsedDocs = [];
|
|
1021
1113
|
for (const file of mdFiles) {
|
|
@@ -1090,149 +1182,404 @@ function runGenerateCode(modulePath, moduleName) {
|
|
|
1090
1182
|
}
|
|
1091
1183
|
}
|
|
1092
1184
|
}
|
|
1185
|
+
const modelDocsDir = path.join(modulePath, "docs", "models");
|
|
1186
|
+
if (fs.existsSync(modelDocsDir)) {
|
|
1187
|
+
const modelFiles = fs.readdirSync(modelDocsDir).filter((f) => f.endsWith(".md"));
|
|
1188
|
+
if (modelFiles.length > 0) {
|
|
1189
|
+
const dbDir = path.join(modulePath, "db");
|
|
1190
|
+
fs.mkdirSync(dbDir, { recursive: true });
|
|
1191
|
+
for (const file of modelFiles) {
|
|
1192
|
+
const modelName = path.basename(file, ".md");
|
|
1193
|
+
const camelName = modelName.charAt(0).toLowerCase() + modelName.slice(1);
|
|
1194
|
+
const dbFile = path.join(dbDir, `${camelName}.ts`);
|
|
1195
|
+
if (!fs.existsSync(dbFile)) {
|
|
1196
|
+
fs.writeFileSync(dbFile, generateDbStub(camelName));
|
|
1197
|
+
console.log(` scaffolded ${path.relative(modulePath, dbFile)}`);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1093
1202
|
console.log(`Generated ${generated} file(s) for ${moduleName}`);
|
|
1094
1203
|
return 0;
|
|
1095
1204
|
}
|
|
1096
1205
|
//#endregion
|
|
1206
|
+
//#region src/commands/generate-doc.ts
|
|
1207
|
+
const MODULE_DOC_TYPES = [
|
|
1208
|
+
"feature",
|
|
1209
|
+
"command",
|
|
1210
|
+
"model",
|
|
1211
|
+
"query"
|
|
1212
|
+
];
|
|
1213
|
+
const APP_DOC_TYPES = [
|
|
1214
|
+
"actors",
|
|
1215
|
+
"business-flow",
|
|
1216
|
+
"story",
|
|
1217
|
+
"screen",
|
|
1218
|
+
"resolver"
|
|
1219
|
+
];
|
|
1220
|
+
[...MODULE_DOC_TYPES, ...APP_DOC_TYPES];
|
|
1221
|
+
const MODULE_DIR_MAP = {
|
|
1222
|
+
feature: MODULE_PATHS.docs.features,
|
|
1223
|
+
command: MODULE_PATHS.docs.commands,
|
|
1224
|
+
model: MODULE_PATHS.docs.models,
|
|
1225
|
+
query: MODULE_PATHS.docs.queries
|
|
1226
|
+
};
|
|
1227
|
+
const APP_DIR_MAP = {
|
|
1228
|
+
actors: APP_PATHS.docs.actors,
|
|
1229
|
+
"business-flow": APP_PATHS.docs.businessFlow,
|
|
1230
|
+
screen: APP_PATHS.docs.screen,
|
|
1231
|
+
resolver: APP_PATHS.docs.resolver
|
|
1232
|
+
};
|
|
1233
|
+
function resolveDocPath(type, name, modulePath) {
|
|
1234
|
+
if (!name) throw new Error(`Name is required for doc type "${type}"`);
|
|
1235
|
+
if (type === "business-flow") return path.join(modulePath, APP_PATHS.docs.businessFlow, name, "README.md");
|
|
1236
|
+
if (type === "story") {
|
|
1237
|
+
const parts = name.split("/");
|
|
1238
|
+
if (parts.length !== 2) throw new Error(`Story name must be "<flow>/<story>" (e.g., "onboarding/admin--create-user")`);
|
|
1239
|
+
return path.join(modulePath, APP_PATHS.docs.businessFlow, parts[0], APP_PATHS.storySegment, `${parts[1]}.md`);
|
|
1240
|
+
}
|
|
1241
|
+
if (MODULE_DIR_MAP[type]) return path.join(modulePath, MODULE_DIR_MAP[type], `${name}.md`);
|
|
1242
|
+
if (APP_DIR_MAP[type]) return path.join(modulePath, APP_DIR_MAP[type], `${name}.md`);
|
|
1243
|
+
throw new Error(`Unknown doc type: ${type}`);
|
|
1244
|
+
}
|
|
1245
|
+
async function runGenerateDoc(type, name, modulePath, cwd) {
|
|
1246
|
+
const outputPath = resolveDocPath(type, name, modulePath);
|
|
1247
|
+
const absoluteOutput = path.resolve(cwd, outputPath);
|
|
1248
|
+
if (fs.existsSync(absoluteOutput)) {
|
|
1249
|
+
console.error(`File already exists: ${outputPath}`);
|
|
1250
|
+
return 1;
|
|
1251
|
+
}
|
|
1252
|
+
const schemaPath = ALL_SCHEMAS[type];
|
|
1253
|
+
if (!schemaPath) {
|
|
1254
|
+
console.error(`No schema found for type: ${type}`);
|
|
1255
|
+
return 2;
|
|
1256
|
+
}
|
|
1257
|
+
try {
|
|
1258
|
+
fs.mkdirSync(path.dirname(absoluteOutput), { recursive: true });
|
|
1259
|
+
} catch (err) {
|
|
1260
|
+
console.error(`Failed to create directory: ${err instanceof Error ? err.message : String(err)}`);
|
|
1261
|
+
return 1;
|
|
1262
|
+
}
|
|
1263
|
+
const { exitCode, stdout, stderr } = await runMdschema([
|
|
1264
|
+
"generate",
|
|
1265
|
+
"--schema",
|
|
1266
|
+
schemaPath,
|
|
1267
|
+
"--output",
|
|
1268
|
+
absoluteOutput
|
|
1269
|
+
], cwd);
|
|
1270
|
+
if (stdout.trim()) console.log(stdout);
|
|
1271
|
+
if (stderr.trim()) console.error(stderr);
|
|
1272
|
+
return exitCode;
|
|
1273
|
+
}
|
|
1274
|
+
//#endregion
|
|
1097
1275
|
//#region src/commands/module/generate.ts
|
|
1098
1276
|
const cwd$3 = process.cwd();
|
|
1099
|
-
const
|
|
1277
|
+
const pathArgs$2 = z.object({ path: arg(z.string(), {
|
|
1278
|
+
alias: "p",
|
|
1279
|
+
description: "Path to the module directory"
|
|
1280
|
+
}) });
|
|
1281
|
+
const generateCommand$1 = defineCommand({
|
|
1100
1282
|
name: "generate",
|
|
1101
|
-
description: "Generate
|
|
1102
|
-
subCommands: {
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1283
|
+
description: "Generate docs and code for a module",
|
|
1284
|
+
subCommands: {
|
|
1285
|
+
doc: defineCommand({
|
|
1286
|
+
name: "doc",
|
|
1287
|
+
description: "Create a documentation file from a schema template",
|
|
1288
|
+
args: pathArgs$2.extend({
|
|
1289
|
+
type: arg(z.enum(MODULE_DOC_TYPES), {
|
|
1290
|
+
positional: true,
|
|
1291
|
+
description: `Doc type (${MODULE_DOC_TYPES.join(", ")})`
|
|
1292
|
+
}),
|
|
1293
|
+
name: arg(z.string().optional(), {
|
|
1294
|
+
positional: true,
|
|
1295
|
+
description: "Item name (required for all types)"
|
|
1296
|
+
})
|
|
1109
1297
|
}),
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1298
|
+
run: (args) => {
|
|
1299
|
+
return executeCommand(async () => {
|
|
1300
|
+
const exitCode = await runGenerateDoc(args.type, args.name, args.path, cwd$3);
|
|
1301
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1114
1304
|
}),
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1305
|
+
code: defineCommand({
|
|
1306
|
+
name: "code",
|
|
1307
|
+
description: "Generate boilerplate, implementation stubs, and generated code from docs",
|
|
1308
|
+
args: pathArgs$2,
|
|
1309
|
+
run: (args) => {
|
|
1310
|
+
return executeCommand(() => {
|
|
1311
|
+
const modulePath = path.resolve(cwd$3, args.path);
|
|
1312
|
+
const moduleName = path.basename(modulePath);
|
|
1313
|
+
console.log(`Generating code for ${moduleName}...`);
|
|
1314
|
+
const exitCode = runGenerateCode(modulePath, moduleName);
|
|
1315
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
})
|
|
1319
|
+
}
|
|
1122
1320
|
});
|
|
1123
1321
|
//#endregion
|
|
1124
1322
|
//#region src/commands/module/index.ts
|
|
1125
1323
|
const cwd$2 = process.cwd();
|
|
1126
|
-
const
|
|
1127
|
-
alias: "
|
|
1324
|
+
const pathArgs$1 = z.object({ path: arg(z.string(), {
|
|
1325
|
+
alias: "p",
|
|
1128
1326
|
description: "Path to modules directory"
|
|
1129
1327
|
}) });
|
|
1130
|
-
const listCommand = defineCommand({
|
|
1131
|
-
name: "list",
|
|
1132
|
-
description: "List available modules",
|
|
1133
|
-
run: () => {
|
|
1134
|
-
const exitCode = runModuleList();
|
|
1135
|
-
process.exit(exitCode);
|
|
1136
|
-
}
|
|
1137
|
-
});
|
|
1138
1328
|
const checkCommand$1 = defineCommand({
|
|
1139
1329
|
name: "check",
|
|
1140
1330
|
description: "Validate module docs against schemas",
|
|
1141
|
-
args:
|
|
1142
|
-
run:
|
|
1143
|
-
|
|
1144
|
-
|
|
1331
|
+
args: pathArgs$1,
|
|
1332
|
+
run: (args) => {
|
|
1333
|
+
return executeCommand(async () => {
|
|
1334
|
+
const exitCode = await runCheck({ modulesRoot: args.path }, cwd$2);
|
|
1335
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
1336
|
+
});
|
|
1145
1337
|
}
|
|
1146
1338
|
});
|
|
1147
1339
|
const syncCheckCommand$1 = defineCommand({
|
|
1148
1340
|
name: "sync-check",
|
|
1149
1341
|
description: "Validate source <-> doc correspondence",
|
|
1150
|
-
args:
|
|
1151
|
-
run:
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1342
|
+
args: pathArgs$1,
|
|
1343
|
+
run: (args) => {
|
|
1344
|
+
return executeCommand(async () => {
|
|
1345
|
+
const result = await runSyncCheck({ modulesRoot: args.path }, cwd$2);
|
|
1346
|
+
console.log(formatSyncCheckReport(result));
|
|
1347
|
+
return result.exitCode === 0 ? success() : silentFailure(result.exitCode);
|
|
1348
|
+
});
|
|
1155
1349
|
}
|
|
1156
1350
|
});
|
|
1157
|
-
const
|
|
1158
|
-
name: "
|
|
1159
|
-
description: "
|
|
1160
|
-
args:
|
|
1161
|
-
|
|
1162
|
-
positional: true,
|
|
1163
|
-
description: `Scaffold type (${MODULE_TYPES.join(", ")})`
|
|
1164
|
-
}),
|
|
1165
|
-
parent: arg(z.string(), {
|
|
1351
|
+
const initCommand$2 = defineCommand({
|
|
1352
|
+
name: "init",
|
|
1353
|
+
description: "Bootstrap a new module with directory structure and README",
|
|
1354
|
+
args: z.object({
|
|
1355
|
+
name: arg(z.string(), {
|
|
1166
1356
|
positional: true,
|
|
1167
1357
|
description: "Module name"
|
|
1168
1358
|
}),
|
|
1169
|
-
|
|
1359
|
+
dir: arg(z.string(), {
|
|
1170
1360
|
positional: true,
|
|
1171
|
-
description: "
|
|
1361
|
+
description: "Parent directory where the module will be created"
|
|
1172
1362
|
})
|
|
1173
1363
|
}),
|
|
1174
|
-
run:
|
|
1175
|
-
|
|
1176
|
-
|
|
1364
|
+
run: (args) => {
|
|
1365
|
+
return executeCommand(async () => {
|
|
1366
|
+
const exitCode = await runInitModuleWithReadme(args.name, args.dir, cwd$2);
|
|
1367
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
1368
|
+
});
|
|
1177
1369
|
}
|
|
1178
1370
|
});
|
|
1179
|
-
const moduleCommand = defineCommand({
|
|
1371
|
+
const moduleCommand$1 = defineCommand({
|
|
1180
1372
|
name: "module",
|
|
1181
1373
|
description: "Module management",
|
|
1182
1374
|
subCommands: {
|
|
1183
|
-
list: listCommand,
|
|
1184
1375
|
check: checkCommand$1,
|
|
1185
1376
|
"sync-check": syncCheckCommand$1,
|
|
1186
|
-
|
|
1187
|
-
generate: generateCommand
|
|
1377
|
+
init: initCommand$2,
|
|
1378
|
+
generate: generateCommand$1
|
|
1188
1379
|
}
|
|
1189
1380
|
});
|
|
1190
1381
|
//#endregion
|
|
1382
|
+
//#region src/generator/parse-resolver-doc.ts
|
|
1383
|
+
const MODULE_COMMAND_PATTERN = /([a-z][\w-]*)\.(\w+)/;
|
|
1384
|
+
const TABLE_ROW_PATTERN = /^\|(.+)\|(.+)\|$/;
|
|
1385
|
+
function parseResolverDoc(fileName, markdown) {
|
|
1386
|
+
return {
|
|
1387
|
+
resolverName: fileName.charAt(0).toLowerCase() + fileName.slice(1),
|
|
1388
|
+
moduleCommands: parseModuleCommands(fromMarkdown(markdown)),
|
|
1389
|
+
errors: parseExceptionHandlingFromRaw(markdown)
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
function isHeading(node) {
|
|
1393
|
+
return node.type === "heading";
|
|
1394
|
+
}
|
|
1395
|
+
function getNodesUnderHeading(tree, headingText) {
|
|
1396
|
+
const nodes = [];
|
|
1397
|
+
let collecting = false;
|
|
1398
|
+
for (const node of tree.children) {
|
|
1399
|
+
if (isHeading(node)) {
|
|
1400
|
+
if (collecting) break;
|
|
1401
|
+
if (node.depth === 2 && toString(node) === headingText) {
|
|
1402
|
+
collecting = true;
|
|
1403
|
+
continue;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
if (collecting) nodes.push(node);
|
|
1407
|
+
}
|
|
1408
|
+
return nodes;
|
|
1409
|
+
}
|
|
1410
|
+
function parseModuleCommands(tree) {
|
|
1411
|
+
const nodes = getNodesUnderHeading(tree, "Modules Commands Used");
|
|
1412
|
+
const commands = [];
|
|
1413
|
+
for (const node of nodes) {
|
|
1414
|
+
if (node.type !== "list") continue;
|
|
1415
|
+
for (const item of node.children) {
|
|
1416
|
+
const text = toString(item);
|
|
1417
|
+
const match = MODULE_COMMAND_PATTERN.exec(text);
|
|
1418
|
+
if (match) commands.push({
|
|
1419
|
+
module: match[1],
|
|
1420
|
+
command: match[2]
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
return commands;
|
|
1425
|
+
}
|
|
1426
|
+
function parseExceptionHandlingFromRaw(markdown) {
|
|
1427
|
+
const lines = markdown.split("\n");
|
|
1428
|
+
const errors = [];
|
|
1429
|
+
let inSection = false;
|
|
1430
|
+
let headerSkipped = false;
|
|
1431
|
+
let separatorSkipped = false;
|
|
1432
|
+
for (const line of lines) {
|
|
1433
|
+
const trimmed = line.trim();
|
|
1434
|
+
if (trimmed.startsWith("## Exception Handling")) {
|
|
1435
|
+
inSection = true;
|
|
1436
|
+
continue;
|
|
1437
|
+
}
|
|
1438
|
+
if (!inSection) continue;
|
|
1439
|
+
if (trimmed.startsWith("#")) break;
|
|
1440
|
+
if (!trimmed) continue;
|
|
1441
|
+
const match = TABLE_ROW_PATTERN.exec(trimmed);
|
|
1442
|
+
if (!match) continue;
|
|
1443
|
+
if (!headerSkipped) {
|
|
1444
|
+
headerSkipped = true;
|
|
1445
|
+
continue;
|
|
1446
|
+
}
|
|
1447
|
+
if (!separatorSkipped) {
|
|
1448
|
+
separatorSkipped = true;
|
|
1449
|
+
continue;
|
|
1450
|
+
}
|
|
1451
|
+
const code = match[1].trim();
|
|
1452
|
+
const description = match[2].trim();
|
|
1453
|
+
if (code) errors.push({
|
|
1454
|
+
code,
|
|
1455
|
+
description
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1458
|
+
return errors;
|
|
1459
|
+
}
|
|
1460
|
+
//#endregion
|
|
1461
|
+
//#region src/generator/generate-app-code.ts
|
|
1462
|
+
function runGenerateAppCode(appPath) {
|
|
1463
|
+
const appName = path.basename(appPath);
|
|
1464
|
+
scaffoldAppBoilerplate(appPath, appName);
|
|
1465
|
+
const docsDir = path.join(appPath, "docs", "resolver");
|
|
1466
|
+
const resolverDir = path.join(appPath, "backend", "src", "resolvers");
|
|
1467
|
+
if (!fs.existsSync(docsDir)) {
|
|
1468
|
+
console.log(`No docs/resolver/ directory found — skipping resolver generation`);
|
|
1469
|
+
console.log(`Generated boilerplate for ${appName}`);
|
|
1470
|
+
return 0;
|
|
1471
|
+
}
|
|
1472
|
+
const mdFiles = fs.readdirSync(docsDir).filter((f) => f.endsWith(".md"));
|
|
1473
|
+
if (mdFiles.length === 0) {
|
|
1474
|
+
console.log(`No resolver docs found — skipping resolver generation`);
|
|
1475
|
+
console.log(`Generated boilerplate for ${appName}`);
|
|
1476
|
+
return 0;
|
|
1477
|
+
}
|
|
1478
|
+
fs.mkdirSync(resolverDir, { recursive: true });
|
|
1479
|
+
let generated = 0;
|
|
1480
|
+
for (const file of mdFiles) {
|
|
1481
|
+
const content = fs.readFileSync(path.join(docsDir, file), "utf-8");
|
|
1482
|
+
const doc = parseResolverDoc(path.basename(file, ".md"), content);
|
|
1483
|
+
const implFile = path.join(resolverDir, `${doc.resolverName}.ts`);
|
|
1484
|
+
if (!fs.existsSync(implFile)) {
|
|
1485
|
+
fs.writeFileSync(implFile, generateResolverStub(doc.resolverName));
|
|
1486
|
+
console.log(` scaffolded ${path.relative(appPath, implFile)}`);
|
|
1487
|
+
generated++;
|
|
1488
|
+
}
|
|
1489
|
+
const testFile = path.join(resolverDir, `${doc.resolverName}.test.ts`);
|
|
1490
|
+
if (!fs.existsSync(testFile)) {
|
|
1491
|
+
fs.writeFileSync(testFile, generateResolverTestStub(doc.resolverName));
|
|
1492
|
+
console.log(` scaffolded ${path.relative(appPath, testFile)}`);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
console.log(`Scaffolded ${generated} resolver(s) for ${appName}`);
|
|
1496
|
+
return 0;
|
|
1497
|
+
}
|
|
1498
|
+
//#endregion
|
|
1191
1499
|
//#region src/commands/app/index.ts
|
|
1192
1500
|
const cwd$1 = process.cwd();
|
|
1193
|
-
const
|
|
1194
|
-
alias: "
|
|
1501
|
+
const pathArgs = z.object({ path: arg(z.string(), {
|
|
1502
|
+
alias: "p",
|
|
1195
1503
|
description: "Path to app-compose directory"
|
|
1196
1504
|
}) });
|
|
1197
1505
|
const checkCommand = defineCommand({
|
|
1198
1506
|
name: "check",
|
|
1199
1507
|
description: "Validate app docs against schemas",
|
|
1200
|
-
args:
|
|
1201
|
-
run:
|
|
1202
|
-
|
|
1203
|
-
|
|
1508
|
+
args: pathArgs,
|
|
1509
|
+
run: (args) => {
|
|
1510
|
+
return executeCommand(async () => {
|
|
1511
|
+
const exitCode = await runCheck({ appRoot: args.path }, cwd$1);
|
|
1512
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
1513
|
+
});
|
|
1204
1514
|
}
|
|
1205
1515
|
});
|
|
1206
1516
|
const syncCheckCommand = defineCommand({
|
|
1207
1517
|
name: "sync-check",
|
|
1208
1518
|
description: "Validate source <-> doc correspondence",
|
|
1209
|
-
args:
|
|
1210
|
-
run:
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1519
|
+
args: pathArgs,
|
|
1520
|
+
run: (args) => {
|
|
1521
|
+
return executeCommand(async () => {
|
|
1522
|
+
const result = await runSyncCheck({ appRoot: args.path }, cwd$1);
|
|
1523
|
+
console.log(formatSyncCheckReport(result));
|
|
1524
|
+
return result.exitCode === 0 ? success() : silentFailure(result.exitCode);
|
|
1525
|
+
});
|
|
1214
1526
|
}
|
|
1215
1527
|
});
|
|
1216
|
-
const
|
|
1217
|
-
name: "
|
|
1218
|
-
description: "
|
|
1219
|
-
args:
|
|
1220
|
-
|
|
1221
|
-
positional: true,
|
|
1222
|
-
description: `Scaffold type (${APP_TYPES.join(", ")})`
|
|
1223
|
-
}),
|
|
1224
|
-
parent: arg(z.string(), {
|
|
1528
|
+
const initCommand$1 = defineCommand({
|
|
1529
|
+
name: "init",
|
|
1530
|
+
description: "Bootstrap a new app with directory structure and README",
|
|
1531
|
+
args: z.object({
|
|
1532
|
+
name: arg(z.string(), {
|
|
1225
1533
|
positional: true,
|
|
1226
1534
|
description: "App name"
|
|
1227
1535
|
}),
|
|
1228
|
-
|
|
1536
|
+
dir: arg(z.string(), {
|
|
1229
1537
|
positional: true,
|
|
1230
|
-
description: "
|
|
1538
|
+
description: "Parent directory where the app will be created"
|
|
1231
1539
|
})
|
|
1232
1540
|
}),
|
|
1233
|
-
run:
|
|
1234
|
-
|
|
1235
|
-
|
|
1541
|
+
run: (args) => {
|
|
1542
|
+
return executeCommand(async () => {
|
|
1543
|
+
const exitCode = await runInitAppWithReadme(args.name, args.dir, cwd$1);
|
|
1544
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
});
|
|
1548
|
+
const generateCommand = defineCommand({
|
|
1549
|
+
name: "generate",
|
|
1550
|
+
description: "Generate docs and code for an app",
|
|
1551
|
+
subCommands: {
|
|
1552
|
+
doc: defineCommand({
|
|
1553
|
+
name: "doc",
|
|
1554
|
+
description: "Create a documentation file from a schema template",
|
|
1555
|
+
args: pathArgs.extend({
|
|
1556
|
+
type: arg(z.enum(APP_DOC_TYPES), {
|
|
1557
|
+
positional: true,
|
|
1558
|
+
description: `Doc type (${APP_DOC_TYPES.join(", ")})`
|
|
1559
|
+
}),
|
|
1560
|
+
name: arg(z.string().optional(), {
|
|
1561
|
+
positional: true,
|
|
1562
|
+
description: "Item name (required for most types)"
|
|
1563
|
+
})
|
|
1564
|
+
}),
|
|
1565
|
+
run: (args) => {
|
|
1566
|
+
return executeCommand(async () => {
|
|
1567
|
+
const exitCode = await runGenerateDoc(args.type, args.name, args.path, cwd$1);
|
|
1568
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1571
|
+
}),
|
|
1572
|
+
code: defineCommand({
|
|
1573
|
+
name: "code",
|
|
1574
|
+
description: "Generate boilerplate source files from docs",
|
|
1575
|
+
args: pathArgs,
|
|
1576
|
+
run: (args) => {
|
|
1577
|
+
return executeCommand(() => {
|
|
1578
|
+
const exitCode = runGenerateAppCode(path.resolve(cwd$1, args.path));
|
|
1579
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1582
|
+
})
|
|
1236
1583
|
}
|
|
1237
1584
|
});
|
|
1238
1585
|
const appCommand = defineCommand({
|
|
@@ -1241,7 +1588,8 @@ const appCommand = defineCommand({
|
|
|
1241
1588
|
subCommands: {
|
|
1242
1589
|
check: checkCommand,
|
|
1243
1590
|
"sync-check": syncCheckCommand,
|
|
1244
|
-
|
|
1591
|
+
init: initCommand$1,
|
|
1592
|
+
generate: generateCommand
|
|
1245
1593
|
}
|
|
1246
1594
|
});
|
|
1247
1595
|
//#endregion
|
|
@@ -1527,9 +1875,11 @@ const mockCommand = defineCommand({
|
|
|
1527
1875
|
description: "Filter by provider or provider/scenario"
|
|
1528
1876
|
})
|
|
1529
1877
|
}),
|
|
1530
|
-
run:
|
|
1531
|
-
|
|
1532
|
-
|
|
1878
|
+
run: (args) => {
|
|
1879
|
+
return executeCommand(async () => {
|
|
1880
|
+
const exitCode = await runMockStart(args.mocksRoot, args.filter, args.port);
|
|
1881
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
1882
|
+
});
|
|
1533
1883
|
}
|
|
1534
1884
|
}),
|
|
1535
1885
|
validate: defineCommand({
|
|
@@ -1542,9 +1892,290 @@ const mockCommand = defineCommand({
|
|
|
1542
1892
|
description: "Specific scenario paths to validate"
|
|
1543
1893
|
})
|
|
1544
1894
|
}),
|
|
1545
|
-
run:
|
|
1546
|
-
|
|
1547
|
-
|
|
1895
|
+
run: (args) => {
|
|
1896
|
+
return executeCommand(async () => {
|
|
1897
|
+
const exitCode = await runMockValidate(args.mocksRoot, args.paths);
|
|
1898
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
1899
|
+
});
|
|
1900
|
+
}
|
|
1901
|
+
})
|
|
1902
|
+
}
|
|
1903
|
+
});
|
|
1904
|
+
//#endregion
|
|
1905
|
+
//#region src/commands/doc/modules.ts
|
|
1906
|
+
const MODULES_DIR$2 = join(PACKAGE_ROOT, "src", "modules");
|
|
1907
|
+
const EXCLUDED_DIRS$2 = new Set(["shared", "testing"]);
|
|
1908
|
+
function countDocs(dir) {
|
|
1909
|
+
if (!existsSync(dir)) return 0;
|
|
1910
|
+
return readdirSync(dir).filter((f) => f.endsWith(".md")).length;
|
|
1911
|
+
}
|
|
1912
|
+
function extractOverview(readmePath) {
|
|
1913
|
+
if (!existsSync(readmePath)) return "";
|
|
1914
|
+
const content = readFileSync(readmePath, "utf-8");
|
|
1915
|
+
const overviewMatch = /## Overview\n\n([\s\S]*?)(?=\n##\s|\n$)/.exec(content);
|
|
1916
|
+
if (!overviewMatch) return "";
|
|
1917
|
+
return overviewMatch[1].trim().split("\n\n")[0];
|
|
1918
|
+
}
|
|
1919
|
+
function extractDependencies(readmePath) {
|
|
1920
|
+
if (!existsSync(readmePath)) return [];
|
|
1921
|
+
const content = readFileSync(readmePath, "utf-8");
|
|
1922
|
+
const depsMatch = /## Module Dependencies\n\n([\s\S]*?)(?=\n##\s|$)/.exec(content);
|
|
1923
|
+
if (!depsMatch) return [];
|
|
1924
|
+
const deps = [];
|
|
1925
|
+
const linePattern = /^- \[([^\]]+)\]/;
|
|
1926
|
+
for (const line of depsMatch[1].trim().split("\n")) {
|
|
1927
|
+
const match = linePattern.exec(line);
|
|
1928
|
+
if (match) deps.push(match[1]);
|
|
1929
|
+
}
|
|
1930
|
+
return deps;
|
|
1931
|
+
}
|
|
1932
|
+
function getModuleOverviews() {
|
|
1933
|
+
if (!existsSync(MODULES_DIR$2)) return [];
|
|
1934
|
+
return readdirSync(MODULES_DIR$2, { withFileTypes: true }).filter((d) => d.isDirectory() && !EXCLUDED_DIRS$2.has(d.name)).map((d) => {
|
|
1935
|
+
const modDir = join(MODULES_DIR$2, d.name);
|
|
1936
|
+
const readmePath = join(modDir, "README.md");
|
|
1937
|
+
return {
|
|
1938
|
+
name: d.name,
|
|
1939
|
+
commandCount: countDocs(join(modDir, MODULE_PATHS.docs.commands)),
|
|
1940
|
+
queryCount: countDocs(join(modDir, MODULE_PATHS.docs.queries)),
|
|
1941
|
+
modelCount: countDocs(join(modDir, MODULE_PATHS.docs.models)),
|
|
1942
|
+
overview: extractOverview(readmePath),
|
|
1943
|
+
dependencies: extractDependencies(readmePath)
|
|
1944
|
+
};
|
|
1945
|
+
}).sort((a, b) => a.name.localeCompare(b.name));
|
|
1946
|
+
}
|
|
1947
|
+
function formatModuleOverviews(modules) {
|
|
1948
|
+
if (modules.length === 0) return "No modules found.";
|
|
1949
|
+
const lines = [];
|
|
1950
|
+
for (const mod of modules) {
|
|
1951
|
+
const counts = [
|
|
1952
|
+
`${mod.commandCount} commands`,
|
|
1953
|
+
`${mod.queryCount} queries`,
|
|
1954
|
+
`${mod.modelCount} models`
|
|
1955
|
+
].join(", ");
|
|
1956
|
+
lines.push(`# ${mod.name} (${counts})`);
|
|
1957
|
+
if (mod.overview) lines.push(mod.overview);
|
|
1958
|
+
if (mod.dependencies.length > 0) lines.push(`Dependencies: ${mod.dependencies.join(", ")}`);
|
|
1959
|
+
else lines.push("Dependencies: none");
|
|
1960
|
+
lines.push("");
|
|
1961
|
+
}
|
|
1962
|
+
lines.push(`${modules.length} modules`);
|
|
1963
|
+
return lines.join("\n");
|
|
1964
|
+
}
|
|
1965
|
+
function runDocModules(format = "text") {
|
|
1966
|
+
const modules = getModuleOverviews();
|
|
1967
|
+
if (format === "json") console.log(JSON.stringify(modules, null, 2));
|
|
1968
|
+
else console.log(formatModuleOverviews(modules));
|
|
1969
|
+
return 0;
|
|
1970
|
+
}
|
|
1971
|
+
//#endregion
|
|
1972
|
+
//#region src/commands/doc/module.ts
|
|
1973
|
+
const MODULES_DIR$1 = join(PACKAGE_ROOT, "src", "modules");
|
|
1974
|
+
const EXCLUDED_DIRS$1 = new Set(["shared", "testing"]);
|
|
1975
|
+
const DOC_TYPE_MAP$1 = {
|
|
1976
|
+
command: MODULE_PATHS.docs.commands,
|
|
1977
|
+
query: MODULE_PATHS.docs.queries,
|
|
1978
|
+
model: MODULE_PATHS.docs.models,
|
|
1979
|
+
feature: MODULE_PATHS.docs.features
|
|
1980
|
+
};
|
|
1981
|
+
function listDocNames(dir) {
|
|
1982
|
+
if (!existsSync(dir)) return [];
|
|
1983
|
+
return readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => f.replace(/\.md$/, "")).sort();
|
|
1984
|
+
}
|
|
1985
|
+
function formatDocList(type, names) {
|
|
1986
|
+
if (names.length === 0) return "";
|
|
1987
|
+
return `${type}: ${names.join(", ")}`;
|
|
1988
|
+
}
|
|
1989
|
+
function runDocModule(moduleName, docType, docName, format = "text") {
|
|
1990
|
+
if (!existsSync(MODULES_DIR$1) || EXCLUDED_DIRS$1.has(moduleName)) {
|
|
1991
|
+
console.error(`Module not found: ${moduleName}`);
|
|
1992
|
+
return 1;
|
|
1993
|
+
}
|
|
1994
|
+
const modDir = join(MODULES_DIR$1, moduleName);
|
|
1995
|
+
if (!existsSync(modDir)) {
|
|
1996
|
+
console.error(`Module not found: ${moduleName}`);
|
|
1997
|
+
const available = readdirSync(MODULES_DIR$1, { withFileTypes: true }).filter((d) => d.isDirectory() && !EXCLUDED_DIRS$1.has(d.name)).map((d) => d.name).sort();
|
|
1998
|
+
console.error(`Available modules: ${available.join(", ")}`);
|
|
1999
|
+
return 1;
|
|
2000
|
+
}
|
|
2001
|
+
if (docType && docName) {
|
|
2002
|
+
const docSubdir = DOC_TYPE_MAP$1[docType];
|
|
2003
|
+
if (!docSubdir) {
|
|
2004
|
+
console.error(`Unknown doc type: ${docType}`);
|
|
2005
|
+
console.error(`Available types: ${Object.keys(DOC_TYPE_MAP$1).join(", ")}`);
|
|
2006
|
+
return 1;
|
|
2007
|
+
}
|
|
2008
|
+
const docPath = join(modDir, docSubdir, `${docName}.md`);
|
|
2009
|
+
if (!existsSync(docPath)) {
|
|
2010
|
+
console.error(`Doc not found: ${moduleName}/${docType}/${docName}`);
|
|
2011
|
+
const available = listDocNames(join(modDir, docSubdir));
|
|
2012
|
+
if (available.length > 0) console.error(`Available ${docType}s: ${available.join(", ")}`);
|
|
2013
|
+
else console.error(`No ${docType} docs found for ${moduleName}`);
|
|
2014
|
+
return 1;
|
|
2015
|
+
}
|
|
2016
|
+
const content = readFileSync(docPath, "utf-8");
|
|
2017
|
+
if (format === "json") console.log(JSON.stringify({
|
|
2018
|
+
module: moduleName,
|
|
2019
|
+
type: docType,
|
|
2020
|
+
name: docName,
|
|
2021
|
+
content
|
|
2022
|
+
}, null, 2));
|
|
2023
|
+
else console.log(content);
|
|
2024
|
+
return 0;
|
|
2025
|
+
}
|
|
2026
|
+
const readmePath = join(modDir, "README.md");
|
|
2027
|
+
const readme = existsSync(readmePath) ? readFileSync(readmePath, "utf-8") : "";
|
|
2028
|
+
const docs = {};
|
|
2029
|
+
for (const [type, subdir] of Object.entries(DOC_TYPE_MAP$1)) {
|
|
2030
|
+
const names = listDocNames(join(modDir, subdir));
|
|
2031
|
+
if (names.length > 0) docs[type] = names;
|
|
2032
|
+
}
|
|
2033
|
+
if (format === "json") console.log(JSON.stringify({
|
|
2034
|
+
module: moduleName,
|
|
2035
|
+
readme,
|
|
2036
|
+
docs
|
|
2037
|
+
}, null, 2));
|
|
2038
|
+
else {
|
|
2039
|
+
if (readme) console.log(readme);
|
|
2040
|
+
else console.log(`# ${moduleName}\n\nNo README found.\n`);
|
|
2041
|
+
const sections = [];
|
|
2042
|
+
for (const [type, names] of Object.entries(docs)) sections.push(formatDocList(type, names));
|
|
2043
|
+
if (sections.length > 0) {
|
|
2044
|
+
console.log("\n## Available Documentation\n");
|
|
2045
|
+
console.log(sections.join("\n"));
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
return 0;
|
|
2049
|
+
}
|
|
2050
|
+
//#endregion
|
|
2051
|
+
//#region src/commands/doc/search.ts
|
|
2052
|
+
const MODULES_DIR = join(PACKAGE_ROOT, "src", "modules");
|
|
2053
|
+
const EXCLUDED_DIRS = new Set(["shared", "testing"]);
|
|
2054
|
+
const DOC_TYPE_MAP = {
|
|
2055
|
+
command: MODULE_PATHS.docs.commands,
|
|
2056
|
+
query: MODULE_PATHS.docs.queries,
|
|
2057
|
+
model: MODULE_PATHS.docs.models,
|
|
2058
|
+
feature: MODULE_PATHS.docs.features
|
|
2059
|
+
};
|
|
2060
|
+
function searchFile(filePath, query, module, type, name) {
|
|
2061
|
+
if (!existsSync(filePath)) return [];
|
|
2062
|
+
const content = readFileSync(filePath, "utf-8");
|
|
2063
|
+
const lowerQuery = query.toLowerCase();
|
|
2064
|
+
const results = [];
|
|
2065
|
+
const lines = content.split("\n");
|
|
2066
|
+
for (let i = 0; i < lines.length; i++) if (lines[i].toLowerCase().includes(lowerQuery)) results.push({
|
|
2067
|
+
module,
|
|
2068
|
+
type,
|
|
2069
|
+
name,
|
|
2070
|
+
line: i + 1,
|
|
2071
|
+
excerpt: lines[i].trim()
|
|
2072
|
+
});
|
|
2073
|
+
return results;
|
|
2074
|
+
}
|
|
2075
|
+
function searchModuleDocs(query, typeFilter) {
|
|
2076
|
+
if (!existsSync(MODULES_DIR)) return [];
|
|
2077
|
+
const results = [];
|
|
2078
|
+
const modules = readdirSync(MODULES_DIR, { withFileTypes: true }).filter((d) => d.isDirectory() && !EXCLUDED_DIRS.has(d.name)).sort((a, b) => a.name.localeCompare(b.name));
|
|
2079
|
+
for (const mod of modules) {
|
|
2080
|
+
const modDir = join(MODULES_DIR, mod.name);
|
|
2081
|
+
if (!typeFilter || typeFilter === "readme") results.push(...searchFile(join(modDir, "README.md"), query, mod.name, "readme", "README"));
|
|
2082
|
+
for (const [type, subdir] of Object.entries(DOC_TYPE_MAP)) {
|
|
2083
|
+
if (typeFilter && typeFilter !== type) continue;
|
|
2084
|
+
const docsDir = join(modDir, subdir);
|
|
2085
|
+
if (!existsSync(docsDir)) continue;
|
|
2086
|
+
const files = readdirSync(docsDir).filter((f) => f.endsWith(".md"));
|
|
2087
|
+
for (const file of files) {
|
|
2088
|
+
const name = file.replace(/\.md$/, "");
|
|
2089
|
+
results.push(...searchFile(join(docsDir, file), query, mod.name, type, name));
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
return results;
|
|
2094
|
+
}
|
|
2095
|
+
function formatSearchResults(results) {
|
|
2096
|
+
if (results.length === 0) return "No results found.";
|
|
2097
|
+
const lines = [];
|
|
2098
|
+
for (const r of results) lines.push(`${r.module}/${r.type}/${r.name}:${r.line}: ${r.excerpt}`);
|
|
2099
|
+
lines.push("");
|
|
2100
|
+
lines.push(`${results.length} matches`);
|
|
2101
|
+
return lines.join("\n");
|
|
2102
|
+
}
|
|
2103
|
+
function runDocSearch(query, type, format = "text") {
|
|
2104
|
+
if (type && type !== "readme" && !(type in DOC_TYPE_MAP)) {
|
|
2105
|
+
console.error(`Unknown doc type: ${type}`);
|
|
2106
|
+
console.error(`Available types: readme, ${Object.keys(DOC_TYPE_MAP).join(", ")}`);
|
|
2107
|
+
return 1;
|
|
2108
|
+
}
|
|
2109
|
+
const results = searchModuleDocs(query, type);
|
|
2110
|
+
if (format === "json") console.log(JSON.stringify(results, null, 2));
|
|
2111
|
+
else console.log(formatSearchResults(results));
|
|
2112
|
+
return 0;
|
|
2113
|
+
}
|
|
2114
|
+
//#endregion
|
|
2115
|
+
//#region src/commands/doc/index.ts
|
|
2116
|
+
const formatArg = arg(z.enum(["text", "json"]).default("text"), {
|
|
2117
|
+
alias: "f",
|
|
2118
|
+
description: "Output format (text or json)"
|
|
2119
|
+
});
|
|
2120
|
+
const docCommand = defineCommand({
|
|
2121
|
+
name: "doc",
|
|
2122
|
+
description: "Browse module documentation",
|
|
2123
|
+
subCommands: {
|
|
2124
|
+
modules: defineCommand({
|
|
2125
|
+
name: "modules",
|
|
2126
|
+
description: "List all modules with capabilities overview",
|
|
2127
|
+
args: z.object({ format: formatArg }),
|
|
2128
|
+
run: (args) => {
|
|
2129
|
+
return executeCommand(() => {
|
|
2130
|
+
const exitCode = runDocModules(args.format);
|
|
2131
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
2132
|
+
});
|
|
2133
|
+
}
|
|
2134
|
+
}),
|
|
2135
|
+
module: defineCommand({
|
|
2136
|
+
name: "module",
|
|
2137
|
+
description: "Show documentation for a specific module",
|
|
2138
|
+
args: z.object({
|
|
2139
|
+
name: arg(z.string(), {
|
|
2140
|
+
positional: true,
|
|
2141
|
+
description: "Module name"
|
|
2142
|
+
}),
|
|
2143
|
+
type: arg(z.string().optional(), {
|
|
2144
|
+
positional: true,
|
|
2145
|
+
description: "Doc type (command, query, model, feature)"
|
|
2146
|
+
}),
|
|
2147
|
+
docName: arg(z.string().optional(), {
|
|
2148
|
+
positional: true,
|
|
2149
|
+
description: "Doc name"
|
|
2150
|
+
}),
|
|
2151
|
+
format: formatArg
|
|
2152
|
+
}),
|
|
2153
|
+
run: (args) => {
|
|
2154
|
+
return executeCommand(() => {
|
|
2155
|
+
const exitCode = runDocModule(args.name, args.type, args.docName, args.format);
|
|
2156
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
2157
|
+
});
|
|
2158
|
+
}
|
|
2159
|
+
}),
|
|
2160
|
+
search: defineCommand({
|
|
2161
|
+
name: "search",
|
|
2162
|
+
description: "Search across all module documentation",
|
|
2163
|
+
args: z.object({
|
|
2164
|
+
query: arg(z.string(), {
|
|
2165
|
+
positional: true,
|
|
2166
|
+
description: "Search query"
|
|
2167
|
+
}),
|
|
2168
|
+
type: arg(z.string().optional(), {
|
|
2169
|
+
alias: "t",
|
|
2170
|
+
description: "Filter by doc type (command, query, model, feature, readme)"
|
|
2171
|
+
}),
|
|
2172
|
+
format: formatArg
|
|
2173
|
+
}),
|
|
2174
|
+
run: (args) => {
|
|
2175
|
+
return executeCommand(() => {
|
|
2176
|
+
const exitCode = runDocSearch(args.query, args.type, args.format);
|
|
2177
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
2178
|
+
});
|
|
1548
2179
|
}
|
|
1549
2180
|
})
|
|
1550
2181
|
}
|
|
@@ -1558,15 +2189,18 @@ runMain(defineCommand({
|
|
|
1558
2189
|
name: "erp-kit",
|
|
1559
2190
|
description: "ERP module framework CLI",
|
|
1560
2191
|
subCommands: {
|
|
1561
|
-
module: moduleCommand,
|
|
2192
|
+
module: moduleCommand$1,
|
|
1562
2193
|
app: appCommand,
|
|
1563
2194
|
mock: mockCommand,
|
|
2195
|
+
doc: docCommand,
|
|
1564
2196
|
init: defineCommand({
|
|
1565
2197
|
name: "init",
|
|
1566
2198
|
description: "First-time setup for a consumer repo",
|
|
1567
2199
|
run: () => {
|
|
1568
|
-
|
|
1569
|
-
|
|
2200
|
+
return executeCommand(() => {
|
|
2201
|
+
const exitCode = runInit(cwd);
|
|
2202
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
2203
|
+
});
|
|
1570
2204
|
}
|
|
1571
2205
|
}),
|
|
1572
2206
|
update: defineCommand({
|
|
@@ -1577,8 +2211,10 @@ runMain(defineCommand({
|
|
|
1577
2211
|
description: "Resources to update (skills, workflows). Defaults to all."
|
|
1578
2212
|
}) }),
|
|
1579
2213
|
run: (args) => {
|
|
1580
|
-
|
|
1581
|
-
|
|
2214
|
+
return executeCommand(() => {
|
|
2215
|
+
const exitCode = runUpdate(cwd, args.resources);
|
|
2216
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
2217
|
+
});
|
|
1582
2218
|
}
|
|
1583
2219
|
}),
|
|
1584
2220
|
license: defineCommand({
|
|
@@ -1593,16 +2229,20 @@ runMain(defineCommand({
|
|
|
1593
2229
|
description: "Path to license config JSON file"
|
|
1594
2230
|
}) }),
|
|
1595
2231
|
run: (args) => {
|
|
1596
|
-
|
|
1597
|
-
|
|
2232
|
+
return executeCommand(() => {
|
|
2233
|
+
const exitCode = runLicenseCheck(args.config);
|
|
2234
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
2235
|
+
});
|
|
1598
2236
|
}
|
|
1599
2237
|
}),
|
|
1600
2238
|
list: defineCommand({
|
|
1601
2239
|
name: "list",
|
|
1602
2240
|
description: "List available license groups",
|
|
1603
2241
|
run: () => {
|
|
1604
|
-
|
|
1605
|
-
|
|
2242
|
+
return executeCommand(() => {
|
|
2243
|
+
const exitCode = runLicenseList();
|
|
2244
|
+
return exitCode === 0 ? success() : silentFailure(exitCode);
|
|
2245
|
+
});
|
|
1606
2246
|
}
|
|
1607
2247
|
})
|
|
1608
2248
|
}
|