@entifix/core 0.1.0-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/LICENSE +21 -0
- package/README.md +11 -0
- package/dist/base-entities/configuration-client/configuration-client-singleton.d.ts +39 -0
- package/dist/base-entities/configuration-client/configuration-client-singleton.d.ts.map +1 -0
- package/dist/base-entities/configuration-client/configuration-client-singleton.js +164 -0
- package/dist/base-entities/configuration-client/configuration-client-singleton.js.map +1 -0
- package/dist/base-entities/configuration-client/index.d.ts +4 -0
- package/dist/base-entities/configuration-client/index.d.ts.map +1 -0
- package/dist/base-entities/configuration-client/index.js +5 -0
- package/dist/base-entities/configuration-client/index.js.map +1 -0
- package/dist/base-entities/configuration-client/read-configuration-from-process.d.ts +11 -0
- package/dist/base-entities/configuration-client/read-configuration-from-process.d.ts.map +1 -0
- package/dist/base-entities/configuration-client/read-configuration-from-process.js +26 -0
- package/dist/base-entities/configuration-client/read-configuration-from-process.js.map +1 -0
- package/dist/base-entities/configuration-client/types.d.ts +38 -0
- package/dist/base-entities/configuration-client/types.d.ts.map +1 -0
- package/dist/base-entities/configuration-client/types.js +3 -0
- package/dist/base-entities/configuration-client/types.js.map +1 -0
- package/dist/base-entities/entifix-error/entifix-error.d.ts +31 -0
- package/dist/base-entities/entifix-error/entifix-error.d.ts.map +1 -0
- package/dist/base-entities/entifix-error/entifix-error.js +56 -0
- package/dist/base-entities/entifix-error/entifix-error.js.map +1 -0
- package/dist/base-entities/entifix-error/index.d.ts +2 -0
- package/dist/base-entities/entifix-error/index.d.ts.map +1 -0
- package/dist/base-entities/entifix-error/index.js +3 -0
- package/dist/base-entities/entifix-error/index.js.map +1 -0
- package/dist/command-palette/command-matching.d.ts +79 -0
- package/dist/command-palette/command-matching.d.ts.map +1 -0
- package/dist/command-palette/command-matching.js +116 -0
- package/dist/command-palette/command-matching.js.map +1 -0
- package/dist/command-palette/command-source.d.ts +109 -0
- package/dist/command-palette/command-source.d.ts.map +1 -0
- package/dist/command-palette/command-source.js +11 -0
- package/dist/command-palette/command-source.js.map +1 -0
- package/dist/command-palette/index.d.ts +3 -0
- package/dist/command-palette/index.d.ts.map +1 -0
- package/dist/command-palette/index.js +4 -0
- package/dist/command-palette/index.js.map +1 -0
- package/dist/entity-definition/decorators/accessor/accessor.d.ts +3 -0
- package/dist/entity-definition/decorators/accessor/accessor.d.ts.map +1 -0
- package/dist/entity-definition/decorators/accessor/accessor.js +11 -0
- package/dist/entity-definition/decorators/accessor/accessor.js.map +1 -0
- package/dist/entity-definition/decorators/accessor/index.d.ts +2 -0
- package/dist/entity-definition/decorators/accessor/index.d.ts.map +1 -0
- package/dist/entity-definition/decorators/accessor/index.js +3 -0
- package/dist/entity-definition/decorators/accessor/index.js.map +1 -0
- package/dist/entity-definition/decorators/entity/entity.d.ts +4 -0
- package/dist/entity-definition/decorators/entity/entity.d.ts.map +1 -0
- package/dist/entity-definition/decorators/entity/entity.js +9 -0
- package/dist/entity-definition/decorators/entity/entity.js.map +1 -0
- package/dist/entity-definition/decorators/entity/index.d.ts +2 -0
- package/dist/entity-definition/decorators/entity/index.d.ts.map +1 -0
- package/dist/entity-definition/decorators/entity/index.js +3 -0
- package/dist/entity-definition/decorators/entity/index.js.map +1 -0
- package/dist/entity-definition/decorators/method/index.d.ts +2 -0
- package/dist/entity-definition/decorators/method/index.d.ts.map +1 -0
- package/dist/entity-definition/decorators/method/index.js +3 -0
- package/dist/entity-definition/decorators/method/index.js.map +1 -0
- package/dist/entity-definition/decorators/method/method.d.ts +3 -0
- package/dist/entity-definition/decorators/method/method.d.ts.map +1 -0
- package/dist/entity-definition/decorators/method/method.js +10 -0
- package/dist/entity-definition/decorators/method/method.js.map +1 -0
- package/dist/entity-definition/decorators/use-case/index.d.ts +2 -0
- package/dist/entity-definition/decorators/use-case/index.d.ts.map +1 -0
- package/dist/entity-definition/decorators/use-case/index.js +3 -0
- package/dist/entity-definition/decorators/use-case/index.js.map +1 -0
- package/dist/entity-definition/decorators/use-case/use-case.d.ts +18 -0
- package/dist/entity-definition/decorators/use-case/use-case.d.ts.map +1 -0
- package/dist/entity-definition/decorators/use-case/use-case.js +26 -0
- package/dist/entity-definition/decorators/use-case/use-case.js.map +1 -0
- package/dist/entity-definition/describe/describe-child-columns.d.ts +33 -0
- package/dist/entity-definition/describe/describe-child-columns.d.ts.map +1 -0
- package/dist/entity-definition/describe/describe-child-columns.js +44 -0
- package/dist/entity-definition/describe/describe-child-columns.js.map +1 -0
- package/dist/entity-definition/describe/describe-entity-columns.d.ts +83 -0
- package/dist/entity-definition/describe/describe-entity-columns.d.ts.map +1 -0
- package/dist/entity-definition/describe/describe-entity-columns.js +112 -0
- package/dist/entity-definition/describe/describe-entity-columns.js.map +1 -0
- package/dist/entity-definition/describe/describe-entity-use-cases.d.ts +34 -0
- package/dist/entity-definition/describe/describe-entity-use-cases.d.ts.map +1 -0
- package/dist/entity-definition/describe/describe-entity-use-cases.js +24 -0
- package/dist/entity-definition/describe/describe-entity-use-cases.js.map +1 -0
- package/dist/entity-definition/describe/index.d.ts +4 -0
- package/dist/entity-definition/describe/index.d.ts.map +1 -0
- package/dist/entity-definition/describe/index.js +5 -0
- package/dist/entity-definition/describe/index.js.map +1 -0
- package/dist/entity-definition/field-path.d.ts +49 -0
- package/dist/entity-definition/field-path.d.ts.map +1 -0
- package/dist/entity-definition/field-path.js +58 -0
- package/dist/entity-definition/field-path.js.map +1 -0
- package/dist/entity-definition/helpers/entity-definition-helpers.d.ts +59 -0
- package/dist/entity-definition/helpers/entity-definition-helpers.d.ts.map +1 -0
- package/dist/entity-definition/helpers/entity-definition-helpers.js +115 -0
- package/dist/entity-definition/helpers/entity-definition-helpers.js.map +1 -0
- package/dist/entity-definition/helpers/index.d.ts +2 -0
- package/dist/entity-definition/helpers/index.d.ts.map +1 -0
- package/dist/entity-definition/helpers/index.js +3 -0
- package/dist/entity-definition/helpers/index.js.map +1 -0
- package/dist/entity-definition/links/apply-entity-links/apply-entity-links.d.ts +48 -0
- package/dist/entity-definition/links/apply-entity-links/apply-entity-links.d.ts.map +1 -0
- package/dist/entity-definition/links/apply-entity-links/apply-entity-links.js +88 -0
- package/dist/entity-definition/links/apply-entity-links/apply-entity-links.js.map +1 -0
- package/dist/entity-definition/links/apply-entity-links/index.d.ts +2 -0
- package/dist/entity-definition/links/apply-entity-links/index.d.ts.map +1 -0
- package/dist/entity-definition/links/apply-entity-links/index.js +3 -0
- package/dist/entity-definition/links/apply-entity-links/index.js.map +1 -0
- package/dist/entity-definition/links/entity-collection-link/entity-collection-link.d.ts +29 -0
- package/dist/entity-definition/links/entity-collection-link/entity-collection-link.d.ts.map +1 -0
- package/dist/entity-definition/links/entity-collection-link/entity-collection-link.js +61 -0
- package/dist/entity-definition/links/entity-collection-link/entity-collection-link.js.map +1 -0
- package/dist/entity-definition/links/entity-collection-link/index.d.ts +2 -0
- package/dist/entity-definition/links/entity-collection-link/index.d.ts.map +1 -0
- package/dist/entity-definition/links/entity-collection-link/index.js +3 -0
- package/dist/entity-definition/links/entity-collection-link/index.js.map +1 -0
- package/dist/entity-definition/links/entity-link/entity-link.d.ts +58 -0
- package/dist/entity-definition/links/entity-link/entity-link.d.ts.map +1 -0
- package/dist/entity-definition/links/entity-link/entity-link.js +79 -0
- package/dist/entity-definition/links/entity-link/entity-link.js.map +1 -0
- package/dist/entity-definition/links/entity-link/index.d.ts +2 -0
- package/dist/entity-definition/links/entity-link/index.d.ts.map +1 -0
- package/dist/entity-definition/links/entity-link/index.js +3 -0
- package/dist/entity-definition/links/entity-link/index.js.map +1 -0
- package/dist/entity-definition/links/entity-link-source/entity-link-source.d.ts +74 -0
- package/dist/entity-definition/links/entity-link-source/entity-link-source.d.ts.map +1 -0
- package/dist/entity-definition/links/entity-link-source/entity-link-source.js +11 -0
- package/dist/entity-definition/links/entity-link-source/entity-link-source.js.map +1 -0
- package/dist/entity-definition/links/entity-link-source/index.d.ts +2 -0
- package/dist/entity-definition/links/entity-link-source/index.d.ts.map +1 -0
- package/dist/entity-definition/links/entity-link-source/index.js +3 -0
- package/dist/entity-definition/links/entity-link-source/index.js.map +1 -0
- package/dist/entity-definition/meta-entities/meta-accessor/index.d.ts +2 -0
- package/dist/entity-definition/meta-entities/meta-accessor/index.d.ts.map +1 -0
- package/dist/entity-definition/meta-entities/meta-accessor/index.js +3 -0
- package/dist/entity-definition/meta-entities/meta-accessor/index.js.map +1 -0
- package/dist/entity-definition/meta-entities/meta-accessor/meta-accessor.d.ts +137 -0
- package/dist/entity-definition/meta-entities/meta-accessor/meta-accessor.d.ts.map +1 -0
- package/dist/entity-definition/meta-entities/meta-accessor/meta-accessor.js +52 -0
- package/dist/entity-definition/meta-entities/meta-accessor/meta-accessor.js.map +1 -0
- package/dist/entity-definition/meta-entities/meta-entity/index.d.ts +2 -0
- package/dist/entity-definition/meta-entities/meta-entity/index.d.ts.map +1 -0
- package/dist/entity-definition/meta-entities/meta-entity/index.js +3 -0
- package/dist/entity-definition/meta-entities/meta-entity/index.js.map +1 -0
- package/dist/entity-definition/meta-entities/meta-entity/meta-entity.d.ts +17 -0
- package/dist/entity-definition/meta-entities/meta-entity/meta-entity.d.ts.map +1 -0
- package/dist/entity-definition/meta-entities/meta-entity/meta-entity.js +13 -0
- package/dist/entity-definition/meta-entities/meta-entity/meta-entity.js.map +1 -0
- package/dist/entity-definition/meta-entities/meta-method/index.d.ts +2 -0
- package/dist/entity-definition/meta-entities/meta-method/index.d.ts.map +1 -0
- package/dist/entity-definition/meta-entities/meta-method/index.js +3 -0
- package/dist/entity-definition/meta-entities/meta-method/index.js.map +1 -0
- package/dist/entity-definition/meta-entities/meta-method/meta-method.d.ts +16 -0
- package/dist/entity-definition/meta-entities/meta-method/meta-method.d.ts.map +1 -0
- package/dist/entity-definition/meta-entities/meta-method/meta-method.js +11 -0
- package/dist/entity-definition/meta-entities/meta-method/meta-method.js.map +1 -0
- package/dist/entity-definition/meta-entities/meta-use-case/index.d.ts +2 -0
- package/dist/entity-definition/meta-entities/meta-use-case/index.d.ts.map +1 -0
- package/dist/entity-definition/meta-entities/meta-use-case/index.js +3 -0
- package/dist/entity-definition/meta-entities/meta-use-case/index.js.map +1 -0
- package/dist/entity-definition/meta-entities/meta-use-case/meta-use-case.d.ts +94 -0
- package/dist/entity-definition/meta-entities/meta-use-case/meta-use-case.d.ts.map +1 -0
- package/dist/entity-definition/meta-entities/meta-use-case/meta-use-case.js +17 -0
- package/dist/entity-definition/meta-entities/meta-use-case/meta-use-case.js.map +1 -0
- package/dist/entity-definition/metadata/entity-metadata-document.d.ts +23 -0
- package/dist/entity-definition/metadata/entity-metadata-document.d.ts.map +1 -0
- package/dist/entity-definition/metadata/entity-metadata-document.js +16 -0
- package/dist/entity-definition/metadata/entity-metadata-document.js.map +1 -0
- package/dist/entity-definition/metadata/entity-metadata-source.d.ts +19 -0
- package/dist/entity-definition/metadata/entity-metadata-source.d.ts.map +1 -0
- package/dist/entity-definition/metadata/entity-metadata-source.js +15 -0
- package/dist/entity-definition/metadata/entity-metadata-source.js.map +1 -0
- package/dist/entity-definition/metadata/index.d.ts +3 -0
- package/dist/entity-definition/metadata/index.d.ts.map +1 -0
- package/dist/entity-definition/metadata/index.js +4 -0
- package/dist/entity-definition/metadata/index.js.map +1 -0
- package/dist/entity-definition/reconstruct/clone-entity-draft.d.ts +34 -0
- package/dist/entity-definition/reconstruct/clone-entity-draft.d.ts.map +1 -0
- package/dist/entity-definition/reconstruct/clone-entity-draft.js +75 -0
- package/dist/entity-definition/reconstruct/clone-entity-draft.js.map +1 -0
- package/dist/entity-definition/reconstruct/coerce-field-value.d.ts +34 -0
- package/dist/entity-definition/reconstruct/coerce-field-value.d.ts.map +1 -0
- package/dist/entity-definition/reconstruct/coerce-field-value.js +42 -0
- package/dist/entity-definition/reconstruct/coerce-field-value.js.map +1 -0
- package/dist/entity-definition/reconstruct/index.d.ts +5 -0
- package/dist/entity-definition/reconstruct/index.d.ts.map +1 -0
- package/dist/entity-definition/reconstruct/index.js +6 -0
- package/dist/entity-definition/reconstruct/index.js.map +1 -0
- package/dist/entity-definition/reconstruct/reconstruct-child.d.ts +35 -0
- package/dist/entity-definition/reconstruct/reconstruct-child.d.ts.map +1 -0
- package/dist/entity-definition/reconstruct/reconstruct-child.js +47 -0
- package/dist/entity-definition/reconstruct/reconstruct-child.js.map +1 -0
- package/dist/entity-definition/reconstruct/reconstruct-entity.d.ts +49 -0
- package/dist/entity-definition/reconstruct/reconstruct-entity.d.ts.map +1 -0
- package/dist/entity-definition/reconstruct/reconstruct-entity.js +116 -0
- package/dist/entity-definition/reconstruct/reconstruct-entity.js.map +1 -0
- package/dist/entity-definition/serializer/deserialize.d.ts +13 -0
- package/dist/entity-definition/serializer/deserialize.d.ts.map +1 -0
- package/dist/entity-definition/serializer/deserialize.js +145 -0
- package/dist/entity-definition/serializer/deserialize.js.map +1 -0
- package/dist/entity-definition/serializer/index.d.ts +3 -0
- package/dist/entity-definition/serializer/index.d.ts.map +1 -0
- package/dist/entity-definition/serializer/index.js +4 -0
- package/dist/entity-definition/serializer/index.js.map +1 -0
- package/dist/entity-definition/serializer/serialize.d.ts +26 -0
- package/dist/entity-definition/serializer/serialize.d.ts.map +1 -0
- package/dist/entity-definition/serializer/serialize.js +64 -0
- package/dist/entity-definition/serializer/serialize.js.map +1 -0
- package/dist/envelope/event-pattern.d.ts +14 -0
- package/dist/envelope/event-pattern.d.ts.map +1 -0
- package/dist/envelope/event-pattern.js +30 -0
- package/dist/envelope/event-pattern.js.map +1 -0
- package/dist/envelope/index.d.ts +5 -0
- package/dist/envelope/index.d.ts.map +1 -0
- package/dist/envelope/index.js +6 -0
- package/dist/envelope/index.js.map +1 -0
- package/dist/envelope/make-envelope.d.ts +45 -0
- package/dist/envelope/make-envelope.d.ts.map +1 -0
- package/dist/envelope/make-envelope.js +111 -0
- package/dist/envelope/make-envelope.js.map +1 -0
- package/dist/envelope/read-envelope.d.ts +48 -0
- package/dist/envelope/read-envelope.d.ts.map +1 -0
- package/dist/envelope/read-envelope.js +138 -0
- package/dist/envelope/read-envelope.js.map +1 -0
- package/dist/envelope/types.d.ts +173 -0
- package/dist/envelope/types.d.ts.map +1 -0
- package/dist/envelope/types.js +6 -0
- package/dist/envelope/types.js.map +1 -0
- package/dist/http/session-cookies.d.ts +25 -0
- package/dist/http/session-cookies.d.ts.map +1 -0
- package/dist/http/session-cookies.js +22 -0
- package/dist/http/session-cookies.js.map +1 -0
- package/dist/i18n/format.d.ts +22 -0
- package/dist/i18n/format.d.ts.map +1 -0
- package/dist/i18n/format.js +49 -0
- package/dist/i18n/format.js.map +1 -0
- package/dist/i18n/index.d.ts +4 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +5 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/locales.d.ts +23 -0
- package/dist/i18n/locales.d.ts.map +1 -0
- package/dist/i18n/locales.js +25 -0
- package/dist/i18n/locales.js.map +1 -0
- package/dist/i18n/negotiate.d.ts +39 -0
- package/dist/i18n/negotiate.d.ts.map +1 -0
- package/dist/i18n/negotiate.js +63 -0
- package/dist/i18n/negotiate.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/rsql/coerce-rsql.d.ts +27 -0
- package/dist/rsql/coerce-rsql.d.ts.map +1 -0
- package/dist/rsql/coerce-rsql.js +121 -0
- package/dist/rsql/coerce-rsql.js.map +1 -0
- package/dist/rsql/index.d.ts +8 -0
- package/dist/rsql/index.d.ts.map +1 -0
- package/dist/rsql/index.js +9 -0
- package/dist/rsql/index.js.map +1 -0
- package/dist/rsql/load-request-url.d.ts +30 -0
- package/dist/rsql/load-request-url.d.ts.map +1 -0
- package/dist/rsql/load-request-url.js +67 -0
- package/dist/rsql/load-request-url.js.map +1 -0
- package/dist/rsql/parse-rsql.d.ts +35 -0
- package/dist/rsql/parse-rsql.d.ts.map +1 -0
- package/dist/rsql/parse-rsql.js +235 -0
- package/dist/rsql/parse-rsql.js.map +1 -0
- package/dist/rsql/rsql-operators.d.ts +36 -0
- package/dist/rsql/rsql-operators.d.ts.map +1 -0
- package/dist/rsql/rsql-operators.js +65 -0
- package/dist/rsql/rsql-operators.js.map +1 -0
- package/dist/rsql/rsql-values.d.ts +11 -0
- package/dist/rsql/rsql-values.d.ts.map +1 -0
- package/dist/rsql/rsql-values.js +26 -0
- package/dist/rsql/rsql-values.js.map +1 -0
- package/dist/rsql/serialize-rsql.d.ts +19 -0
- package/dist/rsql/serialize-rsql.d.ts.map +1 -0
- package/dist/rsql/serialize-rsql.js +71 -0
- package/dist/rsql/serialize-rsql.js.map +1 -0
- package/dist/rsql/sort-param.d.ts +20 -0
- package/dist/rsql/sort-param.d.ts.map +1 -0
- package/dist/rsql/sort-param.js +66 -0
- package/dist/rsql/sort-param.js.map +1 -0
- package/dist/types/BulkOutcome.d.ts +27 -0
- package/dist/types/BulkOutcome.d.ts.map +1 -0
- package/dist/types/BulkOutcome.js +8 -0
- package/dist/types/BulkOutcome.js.map +1 -0
- package/dist/types/Entity.d.ts +6 -0
- package/dist/types/Entity.d.ts.map +1 -0
- package/dist/types/Entity.js +3 -0
- package/dist/types/Entity.js.map +1 -0
- package/dist/types/EntityAction.d.ts +15 -0
- package/dist/types/EntityAction.d.ts.map +1 -0
- package/dist/types/EntityAction.js +18 -0
- package/dist/types/EntityAction.js.map +1 -0
- package/dist/types/EntityDraft.d.ts +47 -0
- package/dist/types/EntityDraft.d.ts.map +1 -0
- package/dist/types/EntityDraft.js +14 -0
- package/dist/types/EntityDraft.js.map +1 -0
- package/dist/types/EntityFiltering.d.ts +45 -0
- package/dist/types/EntityFiltering.d.ts.map +1 -0
- package/dist/types/EntityFiltering.js +30 -0
- package/dist/types/EntityFiltering.js.map +1 -0
- package/dist/types/EntityLoadRequest.d.ts +10 -0
- package/dist/types/EntityLoadRequest.d.ts.map +1 -0
- package/dist/types/EntityLoadRequest.js +3 -0
- package/dist/types/EntityLoadRequest.js.map +1 -0
- package/dist/types/EntityPage.d.ts +8 -0
- package/dist/types/EntityPage.d.ts.map +1 -0
- package/dist/types/EntityPage.js +3 -0
- package/dist/types/EntityPage.js.map +1 -0
- package/dist/types/EntityRowDraft.d.ts +79 -0
- package/dist/types/EntityRowDraft.d.ts.map +1 -0
- package/dist/types/EntityRowDraft.js +65 -0
- package/dist/types/EntityRowDraft.js.map +1 -0
- package/dist/types/EntitySelection.d.ts +117 -0
- package/dist/types/EntitySelection.d.ts.map +1 -0
- package/dist/types/EntitySelection.js +107 -0
- package/dist/types/EntitySelection.js.map +1 -0
- package/dist/types/EntitySorting.d.ts +7 -0
- package/dist/types/EntitySorting.d.ts.map +1 -0
- package/dist/types/EntitySorting.js +3 -0
- package/dist/types/EntitySorting.js.map +1 -0
- package/dist/types/Json.d.ts +37 -0
- package/dist/types/Json.d.ts.map +1 -0
- package/dist/types/Json.js +43 -0
- package/dist/types/Json.js.map +1 -0
- package/dist/types/StandardSchema.d.ts +45 -0
- package/dist/types/StandardSchema.d.ts.map +1 -0
- package/dist/types/StandardSchema.js +15 -0
- package/dist/types/StandardSchema.js.map +1 -0
- package/dist/types/UseCase.d.ts +10 -0
- package/dist/types/UseCase.d.ts.map +1 -0
- package/dist/types/UseCase.js +10 -0
- package/dist/types/UseCase.js.map +1 -0
- package/dist/wizard/index.d.ts +4 -0
- package/dist/wizard/index.d.ts.map +1 -0
- package/dist/wizard/index.js +5 -0
- package/dist/wizard/index.js.map +1 -0
- package/dist/wizard/wizard-definition.d.ts +108 -0
- package/dist/wizard/wizard-definition.d.ts.map +1 -0
- package/dist/wizard/wizard-definition.js +125 -0
- package/dist/wizard/wizard-definition.js.map +1 -0
- package/dist/wizard/wizard-navigation.d.ts +81 -0
- package/dist/wizard/wizard-navigation.d.ts.map +1 -0
- package/dist/wizard/wizard-navigation.js +139 -0
- package/dist/wizard/wizard-navigation.js.map +1 -0
- package/dist/wizard/wizard-state.d.ts +89 -0
- package/dist/wizard/wizard-state.d.ts.map +1 -0
- package/dist/wizard/wizard-state.js +103 -0
- package/dist/wizard/wizard-state.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a UI gets an entity's {@link EntityMetadataDocument} from.
|
|
3
|
+
*
|
|
4
|
+
* A port, for the same reason `EntityLinkSource` is one: the implementation that
|
|
5
|
+
* fetches lives in the client layer, the components that render live in the
|
|
6
|
+
* controls layer, and those two may not import each other — this contract in
|
|
7
|
+
* `core` is what lets them meet. It carries no Effect and no React deliberately.
|
|
8
|
+
*
|
|
9
|
+
* The indirection is also what keeps use-case *implementations* out of a client
|
|
10
|
+
* bundle. A browser must never import a `@useCase()` class: that would drag its
|
|
11
|
+
* `Effect` body, its repository tags and its whole import closure across the
|
|
12
|
+
* wire. It fetches descriptors instead.
|
|
13
|
+
*/ export { };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=entity-metadata-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/entity-definition/metadata/entity-metadata-source.ts"],"sourcesContent":["import type { Entity, EntityConstructor } from '../../types/Entity.js';\nimport type { EntityMetadataDocument } from './entity-metadata-document.js';\n\n/**\n * Where a UI gets an entity's {@link EntityMetadataDocument} from.\n *\n * A port, for the same reason `EntityLinkSource` is one: the implementation that\n * fetches lives in the client layer, the components that render live in the\n * controls layer, and those two may not import each other — this contract in\n * `core` is what lets them meet. It carries no Effect and no React deliberately.\n *\n * The indirection is also what keeps use-case *implementations* out of a client\n * bundle. A browser must never import a `@useCase()` class: that would drag its\n * `Effect` body, its repository tags and its whole import closure across the\n * wire. It fetches descriptors instead.\n */\nexport interface EntityMetadataSource {\n fetchMetadata<TEntity extends Entity>(\n entityConstructor: EntityConstructor<TEntity>,\n ): Promise<EntityMetadataDocument>;\n}\n"],"names":[],"mappings":"AAGA;;;;;;;;;;;;CAYC,GACD,WAIC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/entity-definition/metadata/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/entity-definition/metadata/index.ts"],"sourcesContent":["export * from './entity-metadata-document.js';\nexport * from './entity-metadata-source.js';\n"],"names":[],"mappings":"AAAA,cAAc,gCAAgC;AAC9C,cAAc,8BAA8B"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Entity, EntityConstructor } from '../../types/Entity.js';
|
|
2
|
+
import { EntityDraft } from '../../types/EntityDraft.js';
|
|
3
|
+
/**
|
|
4
|
+
* The draft for a copy of a record: everything the original held, minus the
|
|
5
|
+
* members a copy must not carry.
|
|
6
|
+
*
|
|
7
|
+
* **A draft in and a draft out**, rather than an instance in and an instance
|
|
8
|
+
* out, and that is the whole reason this composes with the rest of the form
|
|
9
|
+
* layer. A form's state is a `Record<string, string>` that a workspace
|
|
10
|
+
* autosaves (ADR 0032), so a clone that returned an instance would have to be
|
|
11
|
+
* re-seeded back into a draft by the caller — through `seedFieldValue`, which
|
|
12
|
+
* lives in a package above this one. Staying in the draft keeps the operation
|
|
13
|
+
* on one side of that boundary, and `reconstructEntity` is still what turns the
|
|
14
|
+
* result into an entity at submit.
|
|
15
|
+
*
|
|
16
|
+
* Two kinds of member are dropped:
|
|
17
|
+
*
|
|
18
|
+
* - **the identity member**, always, with no flag — a copy that carries the
|
|
19
|
+
* original's `id` is an update to the original, which is the one outcome a
|
|
20
|
+
* Clone button must never produce;
|
|
21
|
+
* - **anything declared `@accessor({ resetOnClone: true })`** — a unique code,
|
|
22
|
+
* an audit stamp, a sequence number.
|
|
23
|
+
*
|
|
24
|
+
* Cleared to `''` rather than deleted, because `''` is what an empty control
|
|
25
|
+
* drafts as: a member removed from the record entirely would arrive
|
|
26
|
+
* `undefined`, and an input handed `undefined` flips from controlled to
|
|
27
|
+
* uncontrolled — the same trap `restoreEntityDraft` layers a restored draft
|
|
28
|
+
* over a seeded one to avoid.
|
|
29
|
+
*
|
|
30
|
+
* A member the entity declares but the draft never held stays absent, so this
|
|
31
|
+
* neither invents keys nor widens the draft.
|
|
32
|
+
*/
|
|
33
|
+
export declare function cloneEntityDraft<TEntity extends Entity>(entityConstructor: EntityConstructor<TEntity>, values: EntityDraft): EntityDraft;
|
|
34
|
+
//# sourceMappingURL=clone-entity-draft.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone-entity-draft.d.ts","sourceRoot":"","sources":["../../../src/entity-definition/reconstruct/clone-entity-draft.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAyB,MAAM,4BAA4B,CAAC;AAWhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,SAAS,MAAM,EACrD,iBAAiB,EAAE,iBAAiB,CAAC,OAAO,CAAC,EAC7C,MAAM,EAAE,WAAW,GAClB,WAAW,CA0Bb"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
import { newRowKey, readRowDrafts, ROW_KEY } from '../../types/EntityRowDraft.js';
|
|
3
|
+
import { describeEntityColumns } from '../describe/index.js';
|
|
4
|
+
/** The member `Entity` requires every record to carry. */ const ID_MEMBER = 'id';
|
|
5
|
+
/**
|
|
6
|
+
* The draft for a copy of a record: everything the original held, minus the
|
|
7
|
+
* members a copy must not carry.
|
|
8
|
+
*
|
|
9
|
+
* **A draft in and a draft out**, rather than an instance in and an instance
|
|
10
|
+
* out, and that is the whole reason this composes with the rest of the form
|
|
11
|
+
* layer. A form's state is a `Record<string, string>` that a workspace
|
|
12
|
+
* autosaves (ADR 0032), so a clone that returned an instance would have to be
|
|
13
|
+
* re-seeded back into a draft by the caller — through `seedFieldValue`, which
|
|
14
|
+
* lives in a package above this one. Staying in the draft keeps the operation
|
|
15
|
+
* on one side of that boundary, and `reconstructEntity` is still what turns the
|
|
16
|
+
* result into an entity at submit.
|
|
17
|
+
*
|
|
18
|
+
* Two kinds of member are dropped:
|
|
19
|
+
*
|
|
20
|
+
* - **the identity member**, always, with no flag — a copy that carries the
|
|
21
|
+
* original's `id` is an update to the original, which is the one outcome a
|
|
22
|
+
* Clone button must never produce;
|
|
23
|
+
* - **anything declared `@accessor({ resetOnClone: true })`** — a unique code,
|
|
24
|
+
* an audit stamp, a sequence number.
|
|
25
|
+
*
|
|
26
|
+
* Cleared to `''` rather than deleted, because `''` is what an empty control
|
|
27
|
+
* drafts as: a member removed from the record entirely would arrive
|
|
28
|
+
* `undefined`, and an input handed `undefined` flips from controlled to
|
|
29
|
+
* uncontrolled — the same trap `restoreEntityDraft` layers a restored draft
|
|
30
|
+
* over a seeded one to avoid.
|
|
31
|
+
*
|
|
32
|
+
* A member the entity declares but the draft never held stays absent, so this
|
|
33
|
+
* neither invents keys nor widens the draft.
|
|
34
|
+
*/ export function cloneEntityDraft(entityConstructor, values) {
|
|
35
|
+
const cloned = _extends({}, values);
|
|
36
|
+
// The identity member, cleared **without consulting the descriptors**.
|
|
37
|
+
// `describeEntityColumns` drops `hidden` members, and a form hiding its id is
|
|
38
|
+
// the ordinary case rather than the exotic one — every generated catalog page
|
|
39
|
+
// does it — so a descriptor-driven sweep would leave the id in place on
|
|
40
|
+
// exactly the forms a Clone button appears on, and the "copy" would silently
|
|
41
|
+
// save over the original. `Entity` fixes this member's name, so there is no
|
|
42
|
+
// metadata to consult anyway.
|
|
43
|
+
if (ID_MEMBER in cloned) cloned[ID_MEMBER] = '';
|
|
44
|
+
for (const descriptor of describeEntityColumns(entityConstructor)){
|
|
45
|
+
if (descriptor.type === 'composition') {
|
|
46
|
+
cloned[descriptor.name] = clonedRows(cloned[descriptor.name], descriptor.resetOnClone);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (descriptor.type !== 'id' && !descriptor.resetOnClone) continue;
|
|
50
|
+
if (!(descriptor.name in cloned)) continue;
|
|
51
|
+
cloned[descriptor.name] = '';
|
|
52
|
+
}
|
|
53
|
+
return cloned;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The rows a copy starts with.
|
|
57
|
+
*
|
|
58
|
+
* Two things the `''` rule above cannot express. A collection is **emptied to
|
|
59
|
+
* `[]`, never to `''`**: an empty string is not a readable row list, so
|
|
60
|
+
* `reconstructEntity` would skip the member and the "reset" collection would
|
|
61
|
+
* come back holding the original's lines — a `resetOnClone` that resets nothing.
|
|
62
|
+
*
|
|
63
|
+
* And a row that *is* copied gets a **fresh key**. The key identifies a row
|
|
64
|
+
* within one editing session; carrying the original's over means the copy and
|
|
65
|
+
* the original name their lines identically, so a workspace holding both open
|
|
66
|
+
* has two tabs whose rows claim the same identity — harmless until anything
|
|
67
|
+
* addresses a row across them, and impossible to debug once it does.
|
|
68
|
+
*/ function clonedRows(value, reset) {
|
|
69
|
+
if (reset) return [];
|
|
70
|
+
return readRowDrafts(value).map((row)=>_extends({}, row, {
|
|
71
|
+
[ROW_KEY]: newRowKey()
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
//# sourceMappingURL=clone-entity-draft.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/entity-definition/reconstruct/clone-entity-draft.ts"],"sourcesContent":["import { Entity, EntityConstructor } from '../../types/Entity.js';\nimport { EntityDraft, type EntityDraftValue } from '../../types/EntityDraft.js';\nimport {\n newRowKey,\n readRowDrafts,\n ROW_KEY,\n} from '../../types/EntityRowDraft.js';\nimport { describeEntityColumns } from '../describe/index.js';\n\n/** The member `Entity` requires every record to carry. */\nconst ID_MEMBER = 'id';\n\n/**\n * The draft for a copy of a record: everything the original held, minus the\n * members a copy must not carry.\n *\n * **A draft in and a draft out**, rather than an instance in and an instance\n * out, and that is the whole reason this composes with the rest of the form\n * layer. A form's state is a `Record<string, string>` that a workspace\n * autosaves (ADR 0032), so a clone that returned an instance would have to be\n * re-seeded back into a draft by the caller — through `seedFieldValue`, which\n * lives in a package above this one. Staying in the draft keeps the operation\n * on one side of that boundary, and `reconstructEntity` is still what turns the\n * result into an entity at submit.\n *\n * Two kinds of member are dropped:\n *\n * - **the identity member**, always, with no flag — a copy that carries the\n * original's `id` is an update to the original, which is the one outcome a\n * Clone button must never produce;\n * - **anything declared `@accessor({ resetOnClone: true })`** — a unique code,\n * an audit stamp, a sequence number.\n *\n * Cleared to `''` rather than deleted, because `''` is what an empty control\n * drafts as: a member removed from the record entirely would arrive\n * `undefined`, and an input handed `undefined` flips from controlled to\n * uncontrolled — the same trap `restoreEntityDraft` layers a restored draft\n * over a seeded one to avoid.\n *\n * A member the entity declares but the draft never held stays absent, so this\n * neither invents keys nor widens the draft.\n */\nexport function cloneEntityDraft<TEntity extends Entity>(\n entityConstructor: EntityConstructor<TEntity>,\n values: EntityDraft,\n): EntityDraft {\n const cloned: EntityDraft = { ...values };\n\n // The identity member, cleared **without consulting the descriptors**.\n // `describeEntityColumns` drops `hidden` members, and a form hiding its id is\n // the ordinary case rather than the exotic one — every generated catalog page\n // does it — so a descriptor-driven sweep would leave the id in place on\n // exactly the forms a Clone button appears on, and the \"copy\" would silently\n // save over the original. `Entity` fixes this member's name, so there is no\n // metadata to consult anyway.\n if (ID_MEMBER in cloned) cloned[ID_MEMBER] = '';\n\n for (const descriptor of describeEntityColumns(entityConstructor)) {\n if (descriptor.type === 'composition') {\n cloned[descriptor.name] = clonedRows(\n cloned[descriptor.name],\n descriptor.resetOnClone,\n );\n continue;\n }\n if (descriptor.type !== 'id' && !descriptor.resetOnClone) continue;\n if (!(descriptor.name in cloned)) continue;\n cloned[descriptor.name] = '';\n }\n\n return cloned;\n}\n\n/**\n * The rows a copy starts with.\n *\n * Two things the `''` rule above cannot express. A collection is **emptied to\n * `[]`, never to `''`**: an empty string is not a readable row list, so\n * `reconstructEntity` would skip the member and the \"reset\" collection would\n * come back holding the original's lines — a `resetOnClone` that resets nothing.\n *\n * And a row that *is* copied gets a **fresh key**. The key identifies a row\n * within one editing session; carrying the original's over means the copy and\n * the original name their lines identically, so a workspace holding both open\n * has two tabs whose rows claim the same identity — harmless until anything\n * addresses a row across them, and impossible to debug once it does.\n */\nfunction clonedRows(\n value: EntityDraftValue | undefined,\n reset: boolean,\n): EntityDraftValue {\n if (reset) return [];\n return readRowDrafts(value).map(row => ({ ...row, [ROW_KEY]: newRowKey() }));\n}\n"],"names":["newRowKey","readRowDrafts","ROW_KEY","describeEntityColumns","ID_MEMBER","cloneEntityDraft","entityConstructor","values","cloned","descriptor","type","name","clonedRows","resetOnClone","value","reset","map","row"],"mappings":";AAEA,SACEA,SAAS,EACTC,aAAa,EACbC,OAAO,QACF,gCAAgC;AACvC,SAASC,qBAAqB,QAAQ,uBAAuB;AAE7D,wDAAwD,GACxD,MAAMC,YAAY;AAElB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BC,GACD,OAAO,SAASC,iBACdC,iBAA6C,EAC7CC,MAAmB;IAEnB,MAAMC,SAAsB,aAAKD;IAEjC,uEAAuE;IACvE,8EAA8E;IAC9E,8EAA8E;IAC9E,wEAAwE;IACxE,6EAA6E;IAC7E,4EAA4E;IAC5E,8BAA8B;IAC9B,IAAIH,aAAaI,QAAQA,MAAM,CAACJ,UAAU,GAAG;IAE7C,KAAK,MAAMK,cAAcN,sBAAsBG,mBAAoB;QACjE,IAAIG,WAAWC,IAAI,KAAK,eAAe;YACrCF,MAAM,CAACC,WAAWE,IAAI,CAAC,GAAGC,WACxBJ,MAAM,CAACC,WAAWE,IAAI,CAAC,EACvBF,WAAWI,YAAY;YAEzB;QACF;QACA,IAAIJ,WAAWC,IAAI,KAAK,QAAQ,CAACD,WAAWI,YAAY,EAAE;QAC1D,IAAI,CAAEJ,CAAAA,WAAWE,IAAI,IAAIH,MAAK,GAAI;QAClCA,MAAM,CAACC,WAAWE,IAAI,CAAC,GAAG;IAC5B;IAEA,OAAOH;AACT;AAEA;;;;;;;;;;;;;CAaC,GACD,SAASI,WACPE,KAAmC,EACnCC,KAAc;IAEd,IAAIA,OAAO,OAAO,EAAE;IACpB,OAAOd,cAAca,OAAOE,GAAG,CAACC,CAAAA,MAAQ,aAAKA;YAAK,CAACf,QAAQ,EAAEF;;AAC/D"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { EntityFieldDescriptor } from '../describe/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* The typed value a draft string stands for.
|
|
4
|
+
*
|
|
5
|
+
* This is the exact inverse of the form layer's `seedFieldValue`, and the two
|
|
6
|
+
* have to agree or the round trip is lossy — a member seeded from a record and
|
|
7
|
+
* submitted untouched must come back equal. Two rules are not obvious:
|
|
8
|
+
*
|
|
9
|
+
* - **`boolean` is decided before the empty check, and never yields
|
|
10
|
+
* `undefined`.** A checkbox renders `''` as unchecked, so `''` means `false`;
|
|
11
|
+
* letting the blanket empty rule run first would write `undefined` where the
|
|
12
|
+
* user saw a box they had deliberately left clear.
|
|
13
|
+
* - **`number` checks empty first.** `Number('')` is `0`, so the other order
|
|
14
|
+
* turns every blank numeric field into a real zero.
|
|
15
|
+
*
|
|
16
|
+
* A malformed `number` or `date` is passed through as `NaN` / an invalid `Date`
|
|
17
|
+
* rather than dropped: the form's metadata validation rejects both before
|
|
18
|
+
* submit, and silently discarding a value the user typed would be worse than
|
|
19
|
+
* surfacing it.
|
|
20
|
+
*
|
|
21
|
+
* `scalarCollection` is the one collection with a lossless string form, so it
|
|
22
|
+
* round-trips here rather than waiting for an editor: a comma list in, a
|
|
23
|
+
* `string[]` out. It reads **empty as `[]`, never `undefined`** — a member the
|
|
24
|
+
* user cleared holds no values, which is a different fact from a member that
|
|
25
|
+
* was never set, and only the empty array survives a `required` check honestly.
|
|
26
|
+
* `composition` has no string form at all and never reaches this function; its
|
|
27
|
+
* rows are rebuilt by `reconstructChild`.
|
|
28
|
+
*
|
|
29
|
+
* Extracted from `reconstructEntity` so that a composition's rows coerce through
|
|
30
|
+
* the **same** function their master's scalars do. Two copies of these rules is
|
|
31
|
+
* how a child's `number` member would quietly start meaning something else.
|
|
32
|
+
*/
|
|
33
|
+
export declare function coerceFieldValue(descriptor: EntityFieldDescriptor, raw: string): unknown;
|
|
34
|
+
//# sourceMappingURL=coerce-field-value.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coerce-field-value.d.ts","sourceRoot":"","sources":["../../../src/entity-definition/reconstruct/coerce-field-value.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,qBAAqB,EACjC,GAAG,EAAE,MAAM,GACV,OAAO,CAST"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The typed value a draft string stands for.
|
|
3
|
+
*
|
|
4
|
+
* This is the exact inverse of the form layer's `seedFieldValue`, and the two
|
|
5
|
+
* have to agree or the round trip is lossy — a member seeded from a record and
|
|
6
|
+
* submitted untouched must come back equal. Two rules are not obvious:
|
|
7
|
+
*
|
|
8
|
+
* - **`boolean` is decided before the empty check, and never yields
|
|
9
|
+
* `undefined`.** A checkbox renders `''` as unchecked, so `''` means `false`;
|
|
10
|
+
* letting the blanket empty rule run first would write `undefined` where the
|
|
11
|
+
* user saw a box they had deliberately left clear.
|
|
12
|
+
* - **`number` checks empty first.** `Number('')` is `0`, so the other order
|
|
13
|
+
* turns every blank numeric field into a real zero.
|
|
14
|
+
*
|
|
15
|
+
* A malformed `number` or `date` is passed through as `NaN` / an invalid `Date`
|
|
16
|
+
* rather than dropped: the form's metadata validation rejects both before
|
|
17
|
+
* submit, and silently discarding a value the user typed would be worse than
|
|
18
|
+
* surfacing it.
|
|
19
|
+
*
|
|
20
|
+
* `scalarCollection` is the one collection with a lossless string form, so it
|
|
21
|
+
* round-trips here rather than waiting for an editor: a comma list in, a
|
|
22
|
+
* `string[]` out. It reads **empty as `[]`, never `undefined`** — a member the
|
|
23
|
+
* user cleared holds no values, which is a different fact from a member that
|
|
24
|
+
* was never set, and only the empty array survives a `required` check honestly.
|
|
25
|
+
* `composition` has no string form at all and never reaches this function; its
|
|
26
|
+
* rows are rebuilt by `reconstructChild`.
|
|
27
|
+
*
|
|
28
|
+
* Extracted from `reconstructEntity` so that a composition's rows coerce through
|
|
29
|
+
* the **same** function their master's scalars do. Two copies of these rules is
|
|
30
|
+
* how a child's `number` member would quietly start meaning something else.
|
|
31
|
+
*/ export function coerceFieldValue(descriptor, raw) {
|
|
32
|
+
if (descriptor.type === 'boolean') return raw === 'true';
|
|
33
|
+
if (descriptor.type === 'scalarCollection') {
|
|
34
|
+
return raw === '' ? [] : raw.split(',');
|
|
35
|
+
}
|
|
36
|
+
if (raw === '') return undefined;
|
|
37
|
+
if (descriptor.type === 'number') return Number(raw);
|
|
38
|
+
if (descriptor.type === 'date') return new Date(raw);
|
|
39
|
+
return raw;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=coerce-field-value.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/entity-definition/reconstruct/coerce-field-value.ts"],"sourcesContent":["import type { EntityFieldDescriptor } from '../describe/index.js';\n\n/**\n * The typed value a draft string stands for.\n *\n * This is the exact inverse of the form layer's `seedFieldValue`, and the two\n * have to agree or the round trip is lossy — a member seeded from a record and\n * submitted untouched must come back equal. Two rules are not obvious:\n *\n * - **`boolean` is decided before the empty check, and never yields\n * `undefined`.** A checkbox renders `''` as unchecked, so `''` means `false`;\n * letting the blanket empty rule run first would write `undefined` where the\n * user saw a box they had deliberately left clear.\n * - **`number` checks empty first.** `Number('')` is `0`, so the other order\n * turns every blank numeric field into a real zero.\n *\n * A malformed `number` or `date` is passed through as `NaN` / an invalid `Date`\n * rather than dropped: the form's metadata validation rejects both before\n * submit, and silently discarding a value the user typed would be worse than\n * surfacing it.\n *\n * `scalarCollection` is the one collection with a lossless string form, so it\n * round-trips here rather than waiting for an editor: a comma list in, a\n * `string[]` out. It reads **empty as `[]`, never `undefined`** — a member the\n * user cleared holds no values, which is a different fact from a member that\n * was never set, and only the empty array survives a `required` check honestly.\n * `composition` has no string form at all and never reaches this function; its\n * rows are rebuilt by `reconstructChild`.\n *\n * Extracted from `reconstructEntity` so that a composition's rows coerce through\n * the **same** function their master's scalars do. Two copies of these rules is\n * how a child's `number` member would quietly start meaning something else.\n */\nexport function coerceFieldValue(\n descriptor: EntityFieldDescriptor,\n raw: string,\n): unknown {\n if (descriptor.type === 'boolean') return raw === 'true';\n if (descriptor.type === 'scalarCollection') {\n return raw === '' ? [] : raw.split(',');\n }\n if (raw === '') return undefined;\n if (descriptor.type === 'number') return Number(raw);\n if (descriptor.type === 'date') return new Date(raw);\n return raw;\n}\n"],"names":["coerceFieldValue","descriptor","raw","type","split","undefined","Number","Date"],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BC,GACD,OAAO,SAASA,iBACdC,UAAiC,EACjCC,GAAW;IAEX,IAAID,WAAWE,IAAI,KAAK,WAAW,OAAOD,QAAQ;IAClD,IAAID,WAAWE,IAAI,KAAK,oBAAoB;QAC1C,OAAOD,QAAQ,KAAK,EAAE,GAAGA,IAAIE,KAAK,CAAC;IACrC;IACA,IAAIF,QAAQ,IAAI,OAAOG;IACvB,IAAIJ,WAAWE,IAAI,KAAK,UAAU,OAAOG,OAAOJ;IAChD,IAAID,WAAWE,IAAI,KAAK,QAAQ,OAAO,IAAII,KAAKL;IAChD,OAAOA;AACT"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/entity-definition/reconstruct/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/entity-definition/reconstruct/index.ts"],"sourcesContent":["export * from './clone-entity-draft.js';\nexport * from './coerce-field-value.js';\nexport * from './reconstruct-child.js';\nexport * from './reconstruct-entity.js';\n"],"names":[],"mappings":"AAAA,cAAc,0BAA0B;AACxC,cAAc,0BAA0B;AACxC,cAAc,yBAAyB;AACvC,cAAc,0BAA0B"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { EntityRowDraft } from '../../types/EntityRowDraft.js';
|
|
2
|
+
import type { ChildConstructor } from '../meta-entities/meta-accessor/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Rebuilds one owned row from its draft.
|
|
5
|
+
*
|
|
6
|
+
* The master's own `reconstructEntity` in miniature, and deliberately the same
|
|
7
|
+
* shape: construct zero-argument, then assign through setters, coercing each
|
|
8
|
+
* draft string with the **same** `coerceFieldValue` the master's scalars use.
|
|
9
|
+
* A child that declares `quantity` as a `number` therefore means the same thing
|
|
10
|
+
* on a line as it would on a record.
|
|
11
|
+
*
|
|
12
|
+
* Three rules that are not obvious from the body.
|
|
13
|
+
*
|
|
14
|
+
* **The row key never reaches the child.** It is the browser's identity for the
|
|
15
|
+
* row, not the entity's data — the child is a *value* with no `id` at all — so
|
|
16
|
+
* writing it would put a member on the wire the entity never declared. There is
|
|
17
|
+
* no check for it here because there cannot be one to make: the walk is driven
|
|
18
|
+
* by `describeChildColumns`, which *throws* on a child declaring that name, so
|
|
19
|
+
* no descriptor can ever carry it. A guard here would be unreachable code
|
|
20
|
+
* standing in for an invariant that is already enforced.
|
|
21
|
+
*
|
|
22
|
+
* **A child is never `instanceof`-tested.** `ChildConstructor` is a shape
|
|
23
|
+
* declaration: a row arriving off the wire is a plain object and a row arriving
|
|
24
|
+
* from a draft is JSON, so the constructed instance is the only place the class
|
|
25
|
+
* is real. That is also why the assignment is by `descriptor.name` and not
|
|
26
|
+
* `descriptor.key` — `key` is `alias ?? name`, the storage column, which
|
|
27
|
+
* `serializeEntity` applies a moment later on the way out.
|
|
28
|
+
*
|
|
29
|
+
* **Read-only and nested-collection members are skipped**, matching
|
|
30
|
+
* `editableChildColumns`: a grid cannot write the first, and the second would
|
|
31
|
+
* need a grid inside a grid, which `reconstructChild` is one level too shallow
|
|
32
|
+
* to build by decision rather than by omission.
|
|
33
|
+
*/
|
|
34
|
+
export declare function reconstructChild<TChild extends object>(childType: ChildConstructor<TChild>, row: EntityRowDraft): TChild;
|
|
35
|
+
//# sourceMappingURL=reconstruct-child.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconstruct-child.d.ts","sourceRoot":"","sources":["../../../src/entity-definition/reconstruct/reconstruct-child.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAEpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAGhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,SAAS,MAAM,EACpD,SAAS,EAAE,gBAAgB,CAAC,MAAM,CAAC,EACnC,GAAG,EAAE,cAAc,GAClB,MAAM,CAqBR"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { describeChildColumns } from '../describe/index.js';
|
|
2
|
+
import { coerceFieldValue } from './coerce-field-value.js';
|
|
3
|
+
/**
|
|
4
|
+
* Rebuilds one owned row from its draft.
|
|
5
|
+
*
|
|
6
|
+
* The master's own `reconstructEntity` in miniature, and deliberately the same
|
|
7
|
+
* shape: construct zero-argument, then assign through setters, coercing each
|
|
8
|
+
* draft string with the **same** `coerceFieldValue` the master's scalars use.
|
|
9
|
+
* A child that declares `quantity` as a `number` therefore means the same thing
|
|
10
|
+
* on a line as it would on a record.
|
|
11
|
+
*
|
|
12
|
+
* Three rules that are not obvious from the body.
|
|
13
|
+
*
|
|
14
|
+
* **The row key never reaches the child.** It is the browser's identity for the
|
|
15
|
+
* row, not the entity's data — the child is a *value* with no `id` at all — so
|
|
16
|
+
* writing it would put a member on the wire the entity never declared. There is
|
|
17
|
+
* no check for it here because there cannot be one to make: the walk is driven
|
|
18
|
+
* by `describeChildColumns`, which *throws* on a child declaring that name, so
|
|
19
|
+
* no descriptor can ever carry it. A guard here would be unreachable code
|
|
20
|
+
* standing in for an invariant that is already enforced.
|
|
21
|
+
*
|
|
22
|
+
* **A child is never `instanceof`-tested.** `ChildConstructor` is a shape
|
|
23
|
+
* declaration: a row arriving off the wire is a plain object and a row arriving
|
|
24
|
+
* from a draft is JSON, so the constructed instance is the only place the class
|
|
25
|
+
* is real. That is also why the assignment is by `descriptor.name` and not
|
|
26
|
+
* `descriptor.key` — `key` is `alias ?? name`, the storage column, which
|
|
27
|
+
* `serializeEntity` applies a moment later on the way out.
|
|
28
|
+
*
|
|
29
|
+
* **Read-only and nested-collection members are skipped**, matching
|
|
30
|
+
* `editableChildColumns`: a grid cannot write the first, and the second would
|
|
31
|
+
* need a grid inside a grid, which `reconstructChild` is one level too shallow
|
|
32
|
+
* to build by decision rather than by omission.
|
|
33
|
+
*/ export function reconstructChild(childType, row) {
|
|
34
|
+
const instance = new childType();
|
|
35
|
+
for (const descriptor of describeChildColumns(childType, instance)){
|
|
36
|
+
var _row_descriptor_name;
|
|
37
|
+
if (descriptor.readonly) continue;
|
|
38
|
+
if (descriptor.type === 'composition' || descriptor.type === 'linkCollection' || descriptor.type === 'link') {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
instance[descriptor.name] = coerceFieldValue(descriptor, (_row_descriptor_name = row[descriptor.name]) != null ? _row_descriptor_name : '');
|
|
43
|
+
}
|
|
44
|
+
return instance;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=reconstruct-child.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/entity-definition/reconstruct/reconstruct-child.ts"],"sourcesContent":["import type { EntityRowDraft } from '../../types/EntityRowDraft.js';\nimport { describeChildColumns } from '../describe/index.js';\nimport type { ChildConstructor } from '../meta-entities/meta-accessor/index.js';\nimport { coerceFieldValue } from './coerce-field-value.js';\n\n/**\n * Rebuilds one owned row from its draft.\n *\n * The master's own `reconstructEntity` in miniature, and deliberately the same\n * shape: construct zero-argument, then assign through setters, coercing each\n * draft string with the **same** `coerceFieldValue` the master's scalars use.\n * A child that declares `quantity` as a `number` therefore means the same thing\n * on a line as it would on a record.\n *\n * Three rules that are not obvious from the body.\n *\n * **The row key never reaches the child.** It is the browser's identity for the\n * row, not the entity's data — the child is a *value* with no `id` at all — so\n * writing it would put a member on the wire the entity never declared. There is\n * no check for it here because there cannot be one to make: the walk is driven\n * by `describeChildColumns`, which *throws* on a child declaring that name, so\n * no descriptor can ever carry it. A guard here would be unreachable code\n * standing in for an invariant that is already enforced.\n *\n * **A child is never `instanceof`-tested.** `ChildConstructor` is a shape\n * declaration: a row arriving off the wire is a plain object and a row arriving\n * from a draft is JSON, so the constructed instance is the only place the class\n * is real. That is also why the assignment is by `descriptor.name` and not\n * `descriptor.key` — `key` is `alias ?? name`, the storage column, which\n * `serializeEntity` applies a moment later on the way out.\n *\n * **Read-only and nested-collection members are skipped**, matching\n * `editableChildColumns`: a grid cannot write the first, and the second would\n * need a grid inside a grid, which `reconstructChild` is one level too shallow\n * to build by decision rather than by omission.\n */\nexport function reconstructChild<TChild extends object>(\n childType: ChildConstructor<TChild>,\n row: EntityRowDraft,\n): TChild {\n const instance = new childType();\n\n for (const descriptor of describeChildColumns(childType, instance)) {\n if (descriptor.readonly) continue;\n if (\n descriptor.type === 'composition' ||\n descriptor.type === 'linkCollection' ||\n descriptor.type === 'link'\n ) {\n continue;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (instance as any)[descriptor.name] = coerceFieldValue(\n descriptor,\n row[descriptor.name] ?? '',\n );\n }\n\n return instance;\n}\n"],"names":["describeChildColumns","coerceFieldValue","reconstructChild","childType","row","instance","descriptor","readonly","type","name"],"mappings":"AACA,SAASA,oBAAoB,QAAQ,uBAAuB;AAE5D,SAASC,gBAAgB,QAAQ,0BAA0B;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BC,GACD,OAAO,SAASC,iBACdC,SAAmC,EACnCC,GAAmB;IAEnB,MAAMC,WAAW,IAAIF;IAErB,KAAK,MAAMG,cAAcN,qBAAqBG,WAAWE,UAAW;YAahED;QAZF,IAAIE,WAAWC,QAAQ,EAAE;QACzB,IACED,WAAWE,IAAI,KAAK,iBACpBF,WAAWE,IAAI,KAAK,oBACpBF,WAAWE,IAAI,KAAK,QACpB;YACA;QACF;QAEA,8DAA8D;QAC7DH,QAAgB,CAACC,WAAWG,IAAI,CAAC,GAAGR,iBACnCK,aACAF,uBAAAA,GAAG,CAACE,WAAWG,IAAI,CAAC,YAApBL,uBAAwB;IAE5B;IAEA,OAAOC;AACT"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Entity, EntityConstructor } from '../../types/Entity.js';
|
|
2
|
+
import { EntityDraft } from '../../types/EntityDraft.js';
|
|
3
|
+
import { type EntityLinkSelection } from '../links/apply-entity-links/index.js';
|
|
4
|
+
/** Everything {@link reconstructEntity} needs beyond the draft itself. */
|
|
5
|
+
export interface ReconstructEntityOptions<TEntity extends Entity> {
|
|
6
|
+
/**
|
|
7
|
+
* The record being edited. Supplies the `id` and nothing else — see
|
|
8
|
+
* {@link reconstructEntity} on why it is only the id.
|
|
9
|
+
*/
|
|
10
|
+
existing?: TEntity;
|
|
11
|
+
/**
|
|
12
|
+
* The instances a picker handed over, for members whose declared
|
|
13
|
+
* `linkSerialization` is `embedded`. Passed straight to `applyEntityLinks`.
|
|
14
|
+
*/
|
|
15
|
+
selection?: EntityLinkSelection;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Rebuilds a domain instance from a form's string draft, deriving every
|
|
19
|
+
* assignment from the entity's own accessor metadata.
|
|
20
|
+
*
|
|
21
|
+
* This is the one genuinely hand-written part of an entity form, and writing it
|
|
22
|
+
* per entity is a bug farm: each one repeats the same empty-string-to-undefined
|
|
23
|
+
* rule, and each one has to remember to carry back a member the form hides —
|
|
24
|
+
* `ProductBrand.code` is assigned by the create transaction, and dropping it
|
|
25
|
+
* blanks the record's identifier on every update. Deriving the walk from the
|
|
26
|
+
* metadata makes that structural instead of remembered.
|
|
27
|
+
*
|
|
28
|
+
* **Construction is zero-argument.** `new entityConstructor()` then assignment
|
|
29
|
+
* through setters, the same shape `buildEntityInstance` uses to rebuild a record
|
|
30
|
+
* off the wire. Entities default their constructor parameters, and a required
|
|
31
|
+
* member is filled by its setter a moment later — so required-ness stays one
|
|
32
|
+
* fact (the `@accessor({ required })` flag the form already validates against)
|
|
33
|
+
* rather than a second, unverifiable list of constructor argument names.
|
|
34
|
+
*
|
|
35
|
+
* Constructing first also gives `describeEntityColumns` a sample, which is what
|
|
36
|
+
* lets it infer `link`-ness for an accessor that declared no `type`: relations
|
|
37
|
+
* are initialized by the constructor, so the fresh instance already carries them.
|
|
38
|
+
*
|
|
39
|
+
* **`existing` supplies the id and nothing else.** Every other member comes from
|
|
40
|
+
* the draft, which was seeded from the record — so a create/update distinction
|
|
41
|
+
* lives here once instead of a `target.id = entity?.id` line per form. A draft
|
|
42
|
+
* may be client-supplied (a workspace autosaves it), which is not a new surface:
|
|
43
|
+
* a save route already overwrites the id from its own route parameter.
|
|
44
|
+
*
|
|
45
|
+
* Pure and framework-free, so the same reconstruction runs in a browser form and
|
|
46
|
+
* in a backend use-case assembling an entity from a raw draft.
|
|
47
|
+
*/
|
|
48
|
+
export declare function reconstructEntity<TEntity extends Entity>(entityConstructor: EntityConstructor<TEntity>, values: EntityDraft, { existing, selection }?: ReconstructEntityOptions<TEntity>): TEntity;
|
|
49
|
+
//# sourceMappingURL=reconstruct-entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconstruct-entity.d.ts","sourceRoot":"","sources":["../../../src/entity-definition/reconstruct/reconstruct-entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAmB,MAAM,4BAA4B,CAAC;AAM1E,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,sCAAsC,CAAC;AAM9C,0EAA0E;AAC1E,MAAM,WAAW,wBAAwB,CAAC,OAAO,SAAS,MAAM;IAC9D;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,mBAAmB,CAAC;CACjC;AAmFD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,SAAS,MAAM,EACtD,iBAAiB,EAAE,iBAAiB,CAAC,OAAO,CAAC,EAC7C,MAAM,EAAE,WAAW,EACnB,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAE,wBAAwB,CAAC,OAAO,CAAM,GAC9D,OAAO,CAwBT"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { readDraftString } from '../../types/EntityDraft.js';
|
|
2
|
+
import { isRowDraftArray } from '../../types/EntityRowDraft.js';
|
|
3
|
+
import { describeEntityColumns } from '../describe/index.js';
|
|
4
|
+
import { applyEntityLinks } from '../links/apply-entity-links/index.js';
|
|
5
|
+
import { EntityCollectionLink } from '../links/entity-collection-link/index.js';
|
|
6
|
+
import { EntityLink } from '../links/entity-link/index.js';
|
|
7
|
+
import { coerceFieldValue } from './coerce-field-value.js';
|
|
8
|
+
import { reconstructChild } from './reconstruct-child.js';
|
|
9
|
+
/**
|
|
10
|
+
* Writes an entity's owned collections back from the rows its draft holds.
|
|
11
|
+
*
|
|
12
|
+
* A **second pass** rather than a branch inside the scalar walk, and the reason
|
|
13
|
+
* is the invariant it protects: `isWritableScalar` must go on refusing
|
|
14
|
+
* `composition`, because assigning a coerced string to a member that holds rows
|
|
15
|
+
* is how the master's own lines get blanked on a save that touches nothing else.
|
|
16
|
+
* Keeping the two walks separate means a `composition` is written by exactly one
|
|
17
|
+
* piece of code, and that code cannot be reached with a string.
|
|
18
|
+
*
|
|
19
|
+
* A member whose draft entry is missing or unreadable is **skipped, not
|
|
20
|
+
* cleared** — the same rule the scalar walk applies to a member the form hides.
|
|
21
|
+
* A draft written before this member existed, or one restored from a build that
|
|
22
|
+
* did not know it, must leave the record's rows exactly as they were rather than
|
|
23
|
+
* emptying them, which is a data loss the user never asked for and cannot see.
|
|
24
|
+
* An explicitly empty list *is* a value and is written: that is a user who
|
|
25
|
+
* removed every row.
|
|
26
|
+
*
|
|
27
|
+
* Read-only is honoured for the same reason as everywhere else, and the
|
|
28
|
+
* `childType` guard is not defensive — a `composition` that declared no child
|
|
29
|
+
* has no columns to coerce against, so there is nothing to rebuild.
|
|
30
|
+
*/ function applyEntityComposition(instance, descriptors, values) {
|
|
31
|
+
for (const descriptor of descriptors){
|
|
32
|
+
if (descriptor.type !== 'composition') continue;
|
|
33
|
+
if (descriptor.readonly || descriptor.childType === undefined) continue;
|
|
34
|
+
const drafted = values[descriptor.name];
|
|
35
|
+
if (!isRowDraftArray(drafted)) continue;
|
|
36
|
+
const rows = drafted;
|
|
37
|
+
const childType = descriptor.childType;
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
+
instance[descriptor.name] = rows.map((row)=>reconstructChild(childType, row));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A member this function must not write.
|
|
44
|
+
*
|
|
45
|
+
* `readonly` is the declared half — `describeEntityColumns` keeps read-only
|
|
46
|
+
* members because a form still *shows* them, so unlike the column list this
|
|
47
|
+
* walk has to filter them itself, exactly as `buildEntityInstance` does.
|
|
48
|
+
*
|
|
49
|
+
* The relation half is checked twice on purpose. The declared `link` /
|
|
50
|
+
* `linkCollection` types are `applyEntityLinks`' business, and the runtime
|
|
51
|
+
* `instanceof` catches a bare `@accessor()` on a relation that declared no
|
|
52
|
+
* type: those accessors are getter-only, so assigning a coerced string to one
|
|
53
|
+
* would throw rather than misbehave quietly.
|
|
54
|
+
*
|
|
55
|
+
* `composition` is excluded for the reason `linkCollection` is: it has no
|
|
56
|
+
* editor yet, so a draft never holds its rows and writing one would mean
|
|
57
|
+
* writing `undefined` over the master's own lines on every save. The rows'
|
|
58
|
+
* write path lands with the detail control (#122). `scalarCollection` is *not*
|
|
59
|
+
* excluded — it is a scalar as far as this walk is concerned, because its
|
|
60
|
+
* comma-list draft coerces losslessly back to a `string[]`.
|
|
61
|
+
*/ function isWritableScalar(descriptor, current) {
|
|
62
|
+
if (descriptor.readonly) return false;
|
|
63
|
+
if (descriptor.type === 'link' || descriptor.type === 'linkCollection' || descriptor.type === 'composition') {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
return !(current instanceof EntityLink || current instanceof EntityCollectionLink);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Rebuilds a domain instance from a form's string draft, deriving every
|
|
70
|
+
* assignment from the entity's own accessor metadata.
|
|
71
|
+
*
|
|
72
|
+
* This is the one genuinely hand-written part of an entity form, and writing it
|
|
73
|
+
* per entity is a bug farm: each one repeats the same empty-string-to-undefined
|
|
74
|
+
* rule, and each one has to remember to carry back a member the form hides —
|
|
75
|
+
* `ProductBrand.code` is assigned by the create transaction, and dropping it
|
|
76
|
+
* blanks the record's identifier on every update. Deriving the walk from the
|
|
77
|
+
* metadata makes that structural instead of remembered.
|
|
78
|
+
*
|
|
79
|
+
* **Construction is zero-argument.** `new entityConstructor()` then assignment
|
|
80
|
+
* through setters, the same shape `buildEntityInstance` uses to rebuild a record
|
|
81
|
+
* off the wire. Entities default their constructor parameters, and a required
|
|
82
|
+
* member is filled by its setter a moment later — so required-ness stays one
|
|
83
|
+
* fact (the `@accessor({ required })` flag the form already validates against)
|
|
84
|
+
* rather than a second, unverifiable list of constructor argument names.
|
|
85
|
+
*
|
|
86
|
+
* Constructing first also gives `describeEntityColumns` a sample, which is what
|
|
87
|
+
* lets it infer `link`-ness for an accessor that declared no `type`: relations
|
|
88
|
+
* are initialized by the constructor, so the fresh instance already carries them.
|
|
89
|
+
*
|
|
90
|
+
* **`existing` supplies the id and nothing else.** Every other member comes from
|
|
91
|
+
* the draft, which was seeded from the record — so a create/update distinction
|
|
92
|
+
* lives here once instead of a `target.id = entity?.id` line per form. A draft
|
|
93
|
+
* may be client-supplied (a workspace autosaves it), which is not a new surface:
|
|
94
|
+
* a save route already overwrites the id from its own route parameter.
|
|
95
|
+
*
|
|
96
|
+
* Pure and framework-free, so the same reconstruction runs in a browser form and
|
|
97
|
+
* in a backend use-case assembling an entity from a raw draft.
|
|
98
|
+
*/ export function reconstructEntity(entityConstructor, values, { existing, selection } = {}) {
|
|
99
|
+
const instance = new entityConstructor();
|
|
100
|
+
const descriptors = describeEntityColumns(entityConstructor, instance);
|
|
101
|
+
for (const descriptor of descriptors){
|
|
102
|
+
// The draft is keyed by accessor name, and so is the assignment: `key` is
|
|
103
|
+
// `alias ?? name`, which is the wire/SQL column, not the JS property.
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
105
|
+
const current = instance[descriptor.name];
|
|
106
|
+
if (!isWritableScalar(descriptor, current)) continue;
|
|
107
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
108
|
+
instance[descriptor.name] = coerceFieldValue(descriptor, readDraftString(values, descriptor.name));
|
|
109
|
+
}
|
|
110
|
+
applyEntityComposition(instance, descriptors, values);
|
|
111
|
+
applyEntityLinks(instance, descriptors, values, selection);
|
|
112
|
+
if (existing !== undefined) instance.id = existing.id;
|
|
113
|
+
return instance;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
//# sourceMappingURL=reconstruct-entity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/entity-definition/reconstruct/reconstruct-entity.ts"],"sourcesContent":["import { Entity, EntityConstructor } from '../../types/Entity.js';\nimport { EntityDraft, readDraftString } from '../../types/EntityDraft.js';\nimport { isRowDraftArray } from '../../types/EntityRowDraft.js';\nimport {\n describeEntityColumns,\n EntityFieldDescriptor,\n} from '../describe/index.js';\nimport {\n applyEntityLinks,\n type EntityLinkSelection,\n} from '../links/apply-entity-links/index.js';\nimport { EntityCollectionLink } from '../links/entity-collection-link/index.js';\nimport { EntityLink } from '../links/entity-link/index.js';\nimport { coerceFieldValue } from './coerce-field-value.js';\nimport { reconstructChild } from './reconstruct-child.js';\n\n/** Everything {@link reconstructEntity} needs beyond the draft itself. */\nexport interface ReconstructEntityOptions<TEntity extends Entity> {\n /**\n * The record being edited. Supplies the `id` and nothing else — see\n * {@link reconstructEntity} on why it is only the id.\n */\n existing?: TEntity;\n /**\n * The instances a picker handed over, for members whose declared\n * `linkSerialization` is `embedded`. Passed straight to `applyEntityLinks`.\n */\n selection?: EntityLinkSelection;\n}\n\n/**\n * Writes an entity's owned collections back from the rows its draft holds.\n *\n * A **second pass** rather than a branch inside the scalar walk, and the reason\n * is the invariant it protects: `isWritableScalar` must go on refusing\n * `composition`, because assigning a coerced string to a member that holds rows\n * is how the master's own lines get blanked on a save that touches nothing else.\n * Keeping the two walks separate means a `composition` is written by exactly one\n * piece of code, and that code cannot be reached with a string.\n *\n * A member whose draft entry is missing or unreadable is **skipped, not\n * cleared** — the same rule the scalar walk applies to a member the form hides.\n * A draft written before this member existed, or one restored from a build that\n * did not know it, must leave the record's rows exactly as they were rather than\n * emptying them, which is a data loss the user never asked for and cannot see.\n * An explicitly empty list *is* a value and is written: that is a user who\n * removed every row.\n *\n * Read-only is honoured for the same reason as everywhere else, and the\n * `childType` guard is not defensive — a `composition` that declared no child\n * has no columns to coerce against, so there is nothing to rebuild.\n */\nfunction applyEntityComposition(\n instance: object,\n descriptors: readonly EntityFieldDescriptor[],\n values: EntityDraft,\n): void {\n for (const descriptor of descriptors) {\n if (descriptor.type !== 'composition') continue;\n if (descriptor.readonly || descriptor.childType === undefined) continue;\n\n const drafted = values[descriptor.name];\n if (!isRowDraftArray(drafted)) continue;\n\n const rows = drafted;\n const childType = descriptor.childType;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (instance as any)[descriptor.name] = rows.map(row =>\n reconstructChild(childType, row),\n );\n }\n}\n\n/**\n * A member this function must not write.\n *\n * `readonly` is the declared half — `describeEntityColumns` keeps read-only\n * members because a form still *shows* them, so unlike the column list this\n * walk has to filter them itself, exactly as `buildEntityInstance` does.\n *\n * The relation half is checked twice on purpose. The declared `link` /\n * `linkCollection` types are `applyEntityLinks`' business, and the runtime\n * `instanceof` catches a bare `@accessor()` on a relation that declared no\n * type: those accessors are getter-only, so assigning a coerced string to one\n * would throw rather than misbehave quietly.\n *\n * `composition` is excluded for the reason `linkCollection` is: it has no\n * editor yet, so a draft never holds its rows and writing one would mean\n * writing `undefined` over the master's own lines on every save. The rows'\n * write path lands with the detail control (#122). `scalarCollection` is *not*\n * excluded — it is a scalar as far as this walk is concerned, because its\n * comma-list draft coerces losslessly back to a `string[]`.\n */\nfunction isWritableScalar(\n descriptor: EntityFieldDescriptor,\n current: unknown,\n): boolean {\n if (descriptor.readonly) return false;\n if (\n descriptor.type === 'link' ||\n descriptor.type === 'linkCollection' ||\n descriptor.type === 'composition'\n ) {\n return false;\n }\n return !(\n current instanceof EntityLink || current instanceof EntityCollectionLink\n );\n}\n\n/**\n * Rebuilds a domain instance from a form's string draft, deriving every\n * assignment from the entity's own accessor metadata.\n *\n * This is the one genuinely hand-written part of an entity form, and writing it\n * per entity is a bug farm: each one repeats the same empty-string-to-undefined\n * rule, and each one has to remember to carry back a member the form hides —\n * `ProductBrand.code` is assigned by the create transaction, and dropping it\n * blanks the record's identifier on every update. Deriving the walk from the\n * metadata makes that structural instead of remembered.\n *\n * **Construction is zero-argument.** `new entityConstructor()` then assignment\n * through setters, the same shape `buildEntityInstance` uses to rebuild a record\n * off the wire. Entities default their constructor parameters, and a required\n * member is filled by its setter a moment later — so required-ness stays one\n * fact (the `@accessor({ required })` flag the form already validates against)\n * rather than a second, unverifiable list of constructor argument names.\n *\n * Constructing first also gives `describeEntityColumns` a sample, which is what\n * lets it infer `link`-ness for an accessor that declared no `type`: relations\n * are initialized by the constructor, so the fresh instance already carries them.\n *\n * **`existing` supplies the id and nothing else.** Every other member comes from\n * the draft, which was seeded from the record — so a create/update distinction\n * lives here once instead of a `target.id = entity?.id` line per form. A draft\n * may be client-supplied (a workspace autosaves it), which is not a new surface:\n * a save route already overwrites the id from its own route parameter.\n *\n * Pure and framework-free, so the same reconstruction runs in a browser form and\n * in a backend use-case assembling an entity from a raw draft.\n */\nexport function reconstructEntity<TEntity extends Entity>(\n entityConstructor: EntityConstructor<TEntity>,\n values: EntityDraft,\n { existing, selection }: ReconstructEntityOptions<TEntity> = {},\n): TEntity {\n const instance = new entityConstructor();\n const descriptors = describeEntityColumns(entityConstructor, instance);\n\n for (const descriptor of descriptors) {\n // The draft is keyed by accessor name, and so is the assignment: `key` is\n // `alias ?? name`, which is the wire/SQL column, not the JS property.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const current = (instance as any)[descriptor.name];\n if (!isWritableScalar(descriptor, current)) continue;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (instance as any)[descriptor.name] = coerceFieldValue(\n descriptor,\n readDraftString(values, descriptor.name),\n );\n }\n\n applyEntityComposition(instance, descriptors, values);\n applyEntityLinks(instance, descriptors, values, selection);\n\n if (existing !== undefined) instance.id = existing.id;\n\n return instance;\n}\n"],"names":["readDraftString","isRowDraftArray","describeEntityColumns","applyEntityLinks","EntityCollectionLink","EntityLink","coerceFieldValue","reconstructChild","applyEntityComposition","instance","descriptors","values","descriptor","type","readonly","childType","undefined","drafted","name","rows","map","row","isWritableScalar","current","reconstructEntity","entityConstructor","existing","selection","id"],"mappings":"AACA,SAAsBA,eAAe,QAAQ,6BAA6B;AAC1E,SAASC,eAAe,QAAQ,gCAAgC;AAChE,SACEC,qBAAqB,QAEhB,uBAAuB;AAC9B,SACEC,gBAAgB,QAEX,uCAAuC;AAC9C,SAASC,oBAAoB,QAAQ,2CAA2C;AAChF,SAASC,UAAU,QAAQ,gCAAgC;AAC3D,SAASC,gBAAgB,QAAQ,0BAA0B;AAC3D,SAASC,gBAAgB,QAAQ,yBAAyB;AAgB1D;;;;;;;;;;;;;;;;;;;;;CAqBC,GACD,SAASC,uBACPC,QAAgB,EAChBC,WAA6C,EAC7CC,MAAmB;IAEnB,KAAK,MAAMC,cAAcF,YAAa;QACpC,IAAIE,WAAWC,IAAI,KAAK,eAAe;QACvC,IAAID,WAAWE,QAAQ,IAAIF,WAAWG,SAAS,KAAKC,WAAW;QAE/D,MAAMC,UAAUN,MAAM,CAACC,WAAWM,IAAI,CAAC;QACvC,IAAI,CAACjB,gBAAgBgB,UAAU;QAE/B,MAAME,OAAOF;QACb,MAAMF,YAAYH,WAAWG,SAAS;QAEtC,8DAA8D;QAC7DN,QAAgB,CAACG,WAAWM,IAAI,CAAC,GAAGC,KAAKC,GAAG,CAACC,CAAAA,MAC5Cd,iBAAiBQ,WAAWM;IAEhC;AACF;AAEA;;;;;;;;;;;;;;;;;;;CAmBC,GACD,SAASC,iBACPV,UAAiC,EACjCW,OAAgB;IAEhB,IAAIX,WAAWE,QAAQ,EAAE,OAAO;IAChC,IACEF,WAAWC,IAAI,KAAK,UACpBD,WAAWC,IAAI,KAAK,oBACpBD,WAAWC,IAAI,KAAK,eACpB;QACA,OAAO;IACT;IACA,OAAO,CACLU,CAAAA,mBAAmBlB,cAAckB,mBAAmBnB,oBAAmB;AAE3E;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BC,GACD,OAAO,SAASoB,kBACdC,iBAA6C,EAC7Cd,MAAmB,EACnB,EAAEe,QAAQ,EAAEC,SAAS,EAAqC,GAAG,CAAC,CAAC;IAE/D,MAAMlB,WAAW,IAAIgB;IACrB,MAAMf,cAAcR,sBAAsBuB,mBAAmBhB;IAE7D,KAAK,MAAMG,cAAcF,YAAa;QACpC,0EAA0E;QAC1E,sEAAsE;QACtE,8DAA8D;QAC9D,MAAMa,UAAU,AAACd,QAAgB,CAACG,WAAWM,IAAI,CAAC;QAClD,IAAI,CAACI,iBAAiBV,YAAYW,UAAU;QAE5C,8DAA8D;QAC7Dd,QAAgB,CAACG,WAAWM,IAAI,CAAC,GAAGZ,iBACnCM,YACAZ,gBAAgBW,QAAQC,WAAWM,IAAI;IAE3C;IAEAV,uBAAuBC,UAAUC,aAAaC;IAC9CR,iBAAiBM,UAAUC,aAAaC,QAAQgB;IAEhD,IAAID,aAAaV,WAAWP,SAASmB,EAAE,GAAGF,SAASE,EAAE;IAErD,OAAOnB;AACT"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
import { EntifixBuildError } from '../../base-entities/entifix-error/index.js';
|
|
3
|
+
import { Entity, EntityConstructor } from '../../types/Entity.js';
|
|
4
|
+
/**
|
|
5
|
+
* Result of deserializing a value against an entity constructor. A value can be
|
|
6
|
+
* a single entity, a missing entity (`undefined`) or an arbitrarily nested
|
|
7
|
+
* array of those — which lets collections recurse into arrays of arrays.
|
|
8
|
+
*/
|
|
9
|
+
type DeserializedEntity<TEntity extends Entity> = TEntity | undefined | DeserializedEntity<TEntity>[];
|
|
10
|
+
export declare const deserializeSingleEntity: <TEntity extends Entity>(entityConstructor: EntityConstructor<TEntity>, entityData: unknown) => Effect.Effect<TEntity | undefined, EntifixBuildError, never>;
|
|
11
|
+
export declare const deserializeEntityCollection: <TEntity extends Entity>(entityConstructor: EntityConstructor<TEntity>, entityCollectionData: unknown, failOnNull?: boolean) => Effect.Effect<DeserializedEntity<TEntity>[], EntifixBuildError, never>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=deserialize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deserialize.d.ts","sourceRoot":"","sources":["../../../src/entity-definition/serializer/deserialize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAC/E,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAY,MAAM,uBAAuB,CAAC;AAK5E;;;;GAIG;AACH,KAAK,kBAAkB,CAAC,OAAO,SAAS,MAAM,IAC5C,OAAO,GAAG,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;AA+MtD,eAAO,MAAM,uBAAuB,GAAI,OAAO,SAAS,MAAM,EAC5D,mBAAmB,iBAAiB,CAAC,OAAO,CAAC,EAC7C,YAAY,OAAO,iEAWjB,CAAC;AAEL,eAAO,MAAM,2BAA2B,GAAI,OAAO,SAAS,MAAM,EAChE,mBAAmB,iBAAiB,CAAC,OAAO,CAAC,EAC7C,sBAAsB,OAAO,EAC7B,oBAAkB,2EAgBhB,CAAC"}
|