@aglyn/aglyn 1.0.0-beta.221 → 1.0.0-beta.222
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/package.json +15 -11
- package/src/lib/app-utils/agent-openapi.js +1 -1
- package/src/lib/app-utils/agent-openapi.js.map +1 -1
- package/src/lib/app-utils/analytics-events.d.ts +3 -2
- package/src/lib/app-utils/analytics-events.js +3 -2
- package/src/lib/app-utils/analytics-events.js.map +1 -1
- package/src/lib/app-utils/api-plugins.d.ts +30 -0
- package/src/lib/app-utils/api-plugins.js +24 -1
- package/src/lib/app-utils/api-plugins.js.map +1 -1
- package/src/lib/app-utils/author-html.d.ts +1 -1
- package/src/lib/app-utils/author-html.js.map +1 -1
- package/src/lib/app-utils/bandwidth-cap.d.ts +12 -1
- package/src/lib/app-utils/bandwidth-cap.js +17 -1
- package/src/lib/app-utils/bandwidth-cap.js.map +1 -1
- package/src/lib/app-utils/compose-reusable-components.d.ts +19 -0
- package/src/lib/app-utils/compose-reusable-components.js +116 -26
- package/src/lib/app-utils/compose-reusable-components.js.map +1 -1
- package/src/lib/app-utils/console-routes.d.ts +4 -0
- package/src/lib/app-utils/console-routes.js +3 -0
- package/src/lib/app-utils/console-routes.js.map +1 -1
- package/src/lib/app-utils/contacts.d.ts +71 -0
- package/src/lib/app-utils/contacts.js +55 -0
- package/src/lib/app-utils/contacts.js.map +1 -1
- package/src/lib/app-utils/contexts.d.ts +1 -0
- package/src/lib/app-utils/contexts.js +1 -0
- package/src/lib/app-utils/contexts.js.map +1 -1
- package/src/lib/app-utils/crm-email-templates.js +21 -4
- package/src/lib/app-utils/crm-email-templates.js.map +1 -1
- package/src/lib/app-utils/crm-kinds.d.ts +2 -0
- package/src/lib/app-utils/crm-kinds.js +1 -0
- package/src/lib/app-utils/crm-kinds.js.map +1 -1
- package/src/lib/app-utils/crm.d.ts +1199 -67
- package/src/lib/app-utils/crm.js +1951 -310
- package/src/lib/app-utils/crm.js.map +1 -1
- package/src/lib/app-utils/csv-import.d.ts +10 -38
- package/src/lib/app-utils/csv-import.js +17 -42
- package/src/lib/app-utils/csv-import.js.map +1 -1
- package/src/lib/app-utils/csv.d.ts +32 -11
- package/src/lib/app-utils/csv.js +43 -5
- package/src/lib/app-utils/csv.js.map +1 -1
- package/src/lib/app-utils/default-site.d.ts +116 -0
- package/src/lib/app-utils/default-site.js +1024 -0
- package/src/lib/app-utils/default-site.js.map +1 -0
- package/src/lib/app-utils/docs-help.generated.d.ts +22 -22
- package/src/lib/app-utils/docs-help.generated.js +44 -10
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +738 -150
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/draft-placeholders.d.ts +76 -0
- package/src/lib/app-utils/draft-placeholders.js +115 -0
- package/src/lib/app-utils/draft-placeholders.js.map +1 -0
- package/src/lib/app-utils/entity-picker-context.d.ts +19 -15
- package/src/lib/app-utils/entity-picker-context.js +4 -4
- package/src/lib/app-utils/entity-picker-context.js.map +1 -1
- package/src/lib/app-utils/expand-repeatables.d.ts +66 -10
- package/src/lib/app-utils/expand-repeatables.js +88 -14
- package/src/lib/app-utils/expand-repeatables.js.map +1 -1
- package/src/lib/app-utils/forms.d.ts +33 -22
- package/src/lib/app-utils/forms.js +47 -28
- package/src/lib/app-utils/forms.js.map +1 -1
- package/src/lib/app-utils/full-use-cost.d.ts +277 -0
- package/src/lib/app-utils/full-use-cost.js +421 -0
- package/src/lib/app-utils/full-use-cost.js.map +1 -0
- package/src/lib/app-utils/health-report.js +11 -0
- package/src/lib/app-utils/health-report.js.map +1 -1
- package/src/lib/app-utils/llms-txt.d.ts +20 -0
- package/src/lib/app-utils/llms-txt.js +7 -1
- package/src/lib/app-utils/llms-txt.js.map +1 -1
- package/src/lib/app-utils/media-asset-facts.d.ts +16 -1
- package/src/lib/app-utils/media-asset-facts.js +40 -13
- package/src/lib/app-utils/media-asset-facts.js.map +1 -1
- package/src/lib/app-utils/media-bandwidth.d.ts +52 -0
- package/src/lib/app-utils/media-bandwidth.js +94 -0
- package/src/lib/app-utils/media-bandwidth.js.map +1 -0
- package/src/lib/app-utils/media-ref.d.ts +241 -33
- package/src/lib/app-utils/media-ref.js +324 -43
- package/src/lib/app-utils/media-ref.js.map +1 -1
- package/src/lib/app-utils/media-src.d.ts +8 -8
- package/src/lib/app-utils/media-src.js +27 -11
- package/src/lib/app-utils/media-src.js.map +1 -1
- package/src/lib/app-utils/media-takedown-reach.d.ts +4 -1
- package/src/lib/app-utils/media-takedown-reach.js +6 -3
- package/src/lib/app-utils/media-takedown-reach.js.map +1 -1
- package/src/lib/app-utils/notifications.d.ts +1 -1
- package/src/lib/app-utils/notifications.js +2 -0
- package/src/lib/app-utils/notifications.js.map +1 -1
- package/src/lib/app-utils/organizations.d.ts +51 -2
- package/src/lib/app-utils/organizations.js +56 -3
- package/src/lib/app-utils/organizations.js.map +1 -1
- package/src/lib/app-utils/page-record-sources.d.ts +87 -0
- package/src/lib/app-utils/page-record-sources.js +53 -0
- package/src/lib/app-utils/page-record-sources.js.map +1 -0
- package/src/lib/app-utils/paid-media-source.d.ts +3 -7
- package/src/lib/app-utils/paid-media-source.js +5 -19
- package/src/lib/app-utils/paid-media-source.js.map +1 -1
- package/src/lib/app-utils/person-erasure.d.ts +5 -2
- package/src/lib/app-utils/person-erasure.js.map +1 -1
- package/src/lib/app-utils/picklists.d.ts +187 -0
- package/src/lib/app-utils/picklists.js +320 -0
- package/src/lib/app-utils/picklists.js.map +1 -0
- package/src/lib/app-utils/plan-entitlements.d.ts +220 -50
- package/src/lib/app-utils/plan-entitlements.js +309 -115
- package/src/lib/app-utils/plan-entitlements.js.map +1 -1
- package/src/lib/app-utils/realm-host-surface.generated.js +2 -0
- package/src/lib/app-utils/realm-host-surface.generated.js.map +1 -1
- package/src/lib/app-utils/release-flags.d.ts +1 -1
- package/src/lib/app-utils/release-flags.js +11 -0
- package/src/lib/app-utils/release-flags.js.map +1 -1
- package/src/lib/app-utils/rendered-widths.d.ts +121 -0
- package/src/lib/app-utils/rendered-widths.js +211 -0
- package/src/lib/app-utils/rendered-widths.js.map +1 -0
- package/src/lib/app-utils/repeat-sources.d.ts +2 -1
- package/src/lib/app-utils/repeat-sources.js.map +1 -1
- package/src/lib/app-utils/screen-route.d.ts +154 -36
- package/src/lib/app-utils/screen-route.js +185 -40
- package/src/lib/app-utils/screen-route.js.map +1 -1
- package/src/lib/app-utils/seo-audit.d.ts +11 -1
- package/src/lib/app-utils/seo-audit.js +33 -13
- package/src/lib/app-utils/seo-audit.js.map +1 -1
- package/src/lib/app-utils/seo-keywords.d.ts +11 -0
- package/src/lib/app-utils/seo-keywords.js +19 -5
- package/src/lib/app-utils/seo-keywords.js.map +1 -1
- package/src/lib/app-utils/seo-page-facts.d.ts +47 -4
- package/src/lib/app-utils/seo-page-facts.js +136 -31
- package/src/lib/app-utils/seo-page-facts.js.map +1 -1
- package/src/lib/app-utils/seo-site-scan.d.ts +42 -4
- package/src/lib/app-utils/seo-site-scan.js +113 -12
- package/src/lib/app-utils/seo-site-scan.js.map +1 -1
- package/src/lib/app-utils/server.d.ts +5 -4
- package/src/lib/app-utils/server.js +14 -5
- package/src/lib/app-utils/server.js.map +1 -1
- package/src/lib/app-utils/site-icon-set.d.ts +195 -0
- package/src/lib/app-utils/site-icon-set.js +351 -0
- package/src/lib/app-utils/site-icon-set.js.map +1 -0
- package/src/lib/app-utils/site-interactions.d.ts +101 -4
- package/src/lib/app-utils/site-interactions.js +120 -4
- package/src/lib/app-utils/site-interactions.js.map +1 -1
- package/src/lib/app-utils/starter-template-nodes.d.ts +7 -0
- package/src/lib/app-utils/starter-template-nodes.js +3 -0
- package/src/lib/app-utils/starter-template-nodes.js.map +1 -1
- package/src/lib/app-utils/starter-templates.d.ts +5 -19
- package/src/lib/app-utils/starter-templates.js +5 -49
- package/src/lib/app-utils/starter-templates.js.map +1 -1
- package/src/lib/app-utils/transfer-launcher-context.d.ts +136 -0
- package/src/lib/app-utils/transfer-launcher-context.js +23 -0
- package/src/lib/app-utils/transfer-launcher-context.js.map +1 -0
- package/src/lib/app-utils/transfer-resume-import.d.ts +39 -0
- package/src/lib/app-utils/transfer-resume-import.js +128 -0
- package/src/lib/app-utils/transfer-resume-import.js.map +1 -0
- package/src/lib/app-utils/upgrade-proposal.d.ts +66 -0
- package/src/lib/app-utils/upgrade-proposal.js +95 -0
- package/src/lib/app-utils/upgrade-proposal.js.map +1 -0
- package/src/lib/app-utils/utc-month.d.ts +33 -0
- package/src/lib/app-utils/utc-month.js +35 -0
- package/src/lib/app-utils/utc-month.js.map +1 -0
- package/src/lib/app-utils/visitor-record-ceiling.d.ts +4 -4
- package/src/lib/app-utils/visitor-record-ceiling.js +4 -4
- package/src/lib/app-utils/visitor-record-ceiling.js.map +1 -1
- package/src/lib/app-utils/wire-nodes.d.ts +39 -19
- package/src/lib/app-utils/wire-nodes.js +120 -34
- package/src/lib/app-utils/wire-nodes.js.map +1 -1
- package/src/lib/data-transfer/access.d.ts +74 -0
- package/src/lib/data-transfer/access.js +93 -0
- package/src/lib/data-transfer/access.js.map +1 -0
- package/src/lib/data-transfer/derive.d.ts +246 -0
- package/src/lib/data-transfer/derive.js +1007 -0
- package/src/lib/data-transfer/derive.js.map +1 -0
- package/src/lib/data-transfer/export-file.d.ts +46 -0
- package/src/lib/data-transfer/export-file.js +146 -0
- package/src/lib/data-transfer/export-file.js.map +1 -0
- package/src/lib/data-transfer/field-catalog.d.ts +134 -0
- package/src/lib/data-transfer/field-catalog.js +278 -0
- package/src/lib/data-transfer/field-catalog.js.map +1 -0
- package/src/lib/data-transfer/header-match.d.ts +129 -0
- package/src/lib/data-transfer/header-match.js +367 -0
- package/src/lib/data-transfer/header-match.js.map +1 -0
- package/src/lib/data-transfer/index.d.ts +34 -0
- package/src/lib/data-transfer/index.js +40 -0
- package/src/lib/data-transfer/index.js.map +1 -0
- package/src/lib/data-transfer/job.d.ts +190 -0
- package/src/lib/data-transfer/job.js +229 -0
- package/src/lib/data-transfer/job.js.map +1 -0
- package/src/lib/data-transfer/lookup.d.ts +45 -0
- package/src/lib/data-transfer/lookup.js +71 -0
- package/src/lib/data-transfer/lookup.js.map +1 -0
- package/src/lib/data-transfer/match.d.ts +99 -0
- package/src/lib/data-transfer/match.js +244 -0
- package/src/lib/data-transfer/match.js.map +1 -0
- package/src/lib/data-transfer/package-plan.d.ts +205 -0
- package/src/lib/data-transfer/package-plan.js +475 -0
- package/src/lib/data-transfer/package-plan.js.map +1 -0
- package/src/lib/data-transfer/package.d.ts +181 -0
- package/src/lib/data-transfer/package.js +426 -0
- package/src/lib/data-transfer/package.js.map +1 -0
- package/src/lib/data-transfer/picklist-map.d.ts +139 -0
- package/src/lib/data-transfer/picklist-map.js +271 -0
- package/src/lib/data-transfer/picklist-map.js.map +1 -0
- package/src/lib/data-transfer/plan.d.ts +176 -0
- package/src/lib/data-transfer/plan.js +451 -0
- package/src/lib/data-transfer/plan.js.map +1 -0
- package/src/lib/data-transfer/policy.d.ts +170 -0
- package/src/lib/data-transfer/policy.js +378 -0
- package/src/lib/data-transfer/policy.js.map +1 -0
- package/src/lib/data-transfer/resource.d.ts +211 -0
- package/src/lib/data-transfer/resource.js +241 -0
- package/src/lib/data-transfer/resource.js.map +1 -0
- package/src/lib/data-transfer/review.d.ts +70 -0
- package/src/lib/data-transfer/review.js +233 -0
- package/src/lib/data-transfer/review.js.map +1 -0
- package/src/lib/data-transfer/similarity.d.ts +40 -0
- package/src/lib/data-transfer/similarity.js +106 -0
- package/src/lib/data-transfer/similarity.js.map +1 -0
- package/src/lib/data-transfer/site-package.d.ts +365 -0
- package/src/lib/data-transfer/site-package.js +1077 -0
- package/src/lib/data-transfer/site-package.js.map +1 -0
- package/src/lib/data-transfer/source.d.ts +74 -0
- package/src/lib/data-transfer/source.js +293 -0
- package/src/lib/data-transfer/source.js.map +1 -0
- package/src/lib/data-transfer/transfer-api.d.ts +898 -0
- package/src/lib/data-transfer/transfer-api.js +107 -0
- package/src/lib/data-transfer/transfer-api.js.map +1 -0
- package/src/lib/foundation/definitions/org-billing.types.d.ts +31 -0
- package/src/lib/foundation/definitions/org-billing.types.js.map +1 -1
- package/src/lib/foundation/definitions/organization.types.d.ts +42 -1
- package/src/lib/foundation/definitions/organization.types.js.map +1 -1
- package/src/lib/foundation/definitions/platform.types.d.ts +6 -4
- package/src/lib/foundation/definitions/platform.types.js.map +1 -1
- package/src/lib/foundation/index.d.ts +1 -1
- package/src/lib/foundation/index.js.map +1 -1
- package/src/lib/plugin-manager/feature-plugins.d.ts +91 -2
- package/src/lib/plugin-manager/feature-plugins.js +48 -3
- package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
- package/src/lib/plugin-manager/first-party-plugins.generated.d.ts +50 -0
- package/src/lib/plugin-manager/first-party-plugins.generated.js +1129 -28
- package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
- package/src/lib/plugin-manager/index.d.ts +0 -1
- package/src/lib/plugin-manager/index.js +0 -1
- package/src/lib/plugin-manager/index.js.map +1 -1
- package/src/lib/plugin-manager/interaction-recipes.d.ts +142 -0
- package/src/lib/plugin-manager/interaction-recipes.js +104 -0
- package/src/lib/plugin-manager/interaction-recipes.js.map +1 -0
- package/src/lib/plugin-manager/interaction-step-checks.d.ts +66 -0
- package/src/lib/plugin-manager/interaction-step-checks.js +86 -0
- package/src/lib/plugin-manager/interaction-step-checks.js.map +1 -0
- package/src/lib/plugin-manager/plugin-artifact-types.d.ts +235 -0
- package/src/lib/plugin-manager/plugin-artifact-types.js +99 -0
- package/src/lib/plugin-manager/plugin-artifact-types.js.map +1 -0
- package/src/lib/plugin-manager/plugin-contact-capture.d.ts +8 -0
- package/src/lib/plugin-manager/plugin-contact-capture.js.map +1 -1
- package/src/lib/plugin-manager/plugin-conversion-credit.d.ts +216 -0
- package/src/lib/plugin-manager/plugin-conversion-credit.js +91 -0
- package/src/lib/plugin-manager/plugin-conversion-credit.js.map +1 -0
- package/src/lib/plugin-manager/plugin-entity-pickers.d.ts +83 -0
- package/src/lib/plugin-manager/plugin-entity-pickers.js +87 -0
- package/src/lib/plugin-manager/plugin-entity-pickers.js.map +1 -0
- package/src/lib/plugin-manager/plugin-host-resources.d.ts +6 -0
- package/src/lib/plugin-manager/plugin-host-resources.js +6 -1
- package/src/lib/plugin-manager/plugin-host-resources.js.map +1 -1
- package/src/lib/plugin-manager/plugin-intake-gates.d.ts +75 -0
- package/src/lib/plugin-manager/plugin-intake-gates.js +49 -0
- package/src/lib/plugin-manager/plugin-intake-gates.js.map +1 -0
- package/src/lib/plugin-manager/plugin-jobs.d.ts +5 -5
- package/src/lib/plugin-manager/plugin-jobs.js +7 -7
- package/src/lib/plugin-manager/plugin-jobs.js.map +1 -1
- package/src/lib/plugin-manager/plugin-live-paths.d.ts +70 -0
- package/src/lib/plugin-manager/plugin-live-paths.js +66 -0
- package/src/lib/plugin-manager/plugin-live-paths.js.map +1 -0
- package/src/lib/plugin-manager/plugin-org-erasure.d.ts +3 -2
- package/src/lib/plugin-manager/plugin-org-erasure.js +30 -5
- package/src/lib/plugin-manager/plugin-org-erasure.js.map +1 -1
- package/src/lib/plugin-manager/plugin-person-erasure.d.ts +68 -9
- package/src/lib/plugin-manager/plugin-person-erasure.js +196 -51
- package/src/lib/plugin-manager/plugin-person-erasure.js.map +1 -1
- package/src/lib/plugin-manager/plugin-person-records.d.ts +275 -0
- package/src/lib/plugin-manager/plugin-person-records.js +107 -0
- package/src/lib/plugin-manager/plugin-person-records.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-counts.d.ts +76 -0
- package/src/lib/plugin-manager/plugin-record-counts.js +49 -0
- package/src/lib/plugin-manager/plugin-record-counts.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-email-state.d.ts +26 -0
- package/src/lib/plugin-manager/plugin-record-email-state.js +16 -0
- package/src/lib/plugin-manager/plugin-record-email-state.js.map +1 -1
- package/src/lib/plugin-manager/plugin-record-index.d.ts +10 -0
- package/src/lib/plugin-manager/plugin-record-index.js.map +1 -1
- package/src/lib/plugin-manager/plugin-record-lists.d.ts +86 -6
- package/src/lib/plugin-manager/plugin-record-lists.js +42 -5
- package/src/lib/plugin-manager/plugin-record-lists.js.map +1 -1
- package/src/lib/plugin-manager/plugin-record-origin.d.ts +79 -0
- package/src/lib/plugin-manager/plugin-record-origin.js +46 -0
- package/src/lib/plugin-manager/plugin-record-origin.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-pages.d.ts +37 -0
- package/src/lib/plugin-manager/plugin-record-pages.js +52 -0
- package/src/lib/plugin-manager/plugin-record-pages.js.map +1 -0
- package/src/lib/plugin-manager/plugin-record-timeline.d.ts +60 -0
- package/src/lib/plugin-manager/plugin-record-timeline.js +16 -0
- package/src/lib/plugin-manager/plugin-record-timeline.js.map +1 -1
- package/src/lib/plugin-manager/plugin-resource-drafts.d.ts +5 -5
- package/src/lib/plugin-manager/plugin-resource-drafts.js.map +1 -1
- package/src/lib/plugin-manager/plugin-revocations.d.ts +64 -0
- package/src/lib/plugin-manager/plugin-revocations.js +47 -0
- package/src/lib/plugin-manager/plugin-revocations.js.map +1 -0
- package/src/lib/plugin-manager/plugin-send-tallies.d.ts +69 -0
- package/src/lib/plugin-manager/plugin-send-tallies.js +45 -0
- package/src/lib/plugin-manager/plugin-send-tallies.js.map +1 -0
- package/src/lib/plugin-manager/plugin-site-bundle.d.ts +40 -0
- package/src/lib/plugin-manager/plugin-site-bundle.js +4 -0
- package/src/lib/plugin-manager/plugin-site-bundle.js.map +1 -1
- package/src/lib/plugin-manager/plugin-site-export.d.ts +57 -1
- package/src/lib/plugin-manager/plugin-site-export.js +23 -10
- package/src/lib/plugin-manager/plugin-site-export.js.map +1 -1
- package/src/lib/plugin-manager/plugin-sitemap-readers.d.ts +146 -0
- package/src/lib/plugin-manager/plugin-sitemap-readers.js +110 -0
- package/src/lib/plugin-manager/plugin-sitemap-readers.js.map +1 -0
- package/src/lib/plugin-manager/plugin-transfer-resources.d.ts +714 -0
- package/src/lib/plugin-manager/plugin-transfer-resources.js +443 -0
- package/src/lib/plugin-manager/plugin-transfer-resources.js.map +1 -0
- package/src/lib/plugin-manager/plugin-usage-axes.d.ts +54 -5
- package/src/lib/plugin-manager/plugin-usage-axes.js +11 -3
- package/src/lib/plugin-manager/plugin-usage-axes.js.map +1 -1
- package/src/lib/plugin-manager/plugin-user-erasure.js +9 -1
- package/src/lib/plugin-manager/plugin-user-erasure.js.map +1 -1
- package/src/lib/plugin-manager/plugin-visitor-doors.d.ts +104 -0
- package/src/lib/plugin-manager/plugin-visitor-doors.js +108 -0
- package/src/lib/plugin-manager/plugin-visitor-doors.js.map +1 -0
- package/src/lib/plugin-manager/realm-host-aglyn.generated.js +2 -0
- package/src/lib/plugin-manager/realm-host-aglyn.generated.js.map +1 -1
- package/src/lib/plugin-manager/repeat-rows.d.ts +5 -6
- package/src/lib/plugin-manager/repeat-rows.js.map +1 -1
- package/src/lib/app-utils/actions.d.ts +0 -310
- package/src/lib/app-utils/actions.js +0 -506
- package/src/lib/app-utils/actions.js.map +0 -1
- package/src/lib/app-utils/automation-placeholders.d.ts +0 -72
- package/src/lib/app-utils/automation-placeholders.js +0 -207
- package/src/lib/app-utils/automation-placeholders.js.map +0 -1
- package/src/lib/app-utils/dataset-models.d.ts +0 -339
- package/src/lib/app-utils/dataset-models.js +0 -722
- package/src/lib/app-utils/dataset-models.js.map +0 -1
- package/src/lib/app-utils/datasets.d.ts +0 -171
- package/src/lib/app-utils/datasets.js +0 -227
- package/src/lib/app-utils/datasets.js.map +0 -1
- package/src/lib/app-utils/form-abuse-ceiling.d.ts +0 -146
- package/src/lib/app-utils/form-abuse-ceiling.js +0 -158
- package/src/lib/app-utils/form-abuse-ceiling.js.map +0 -1
- package/src/lib/plugin-manager/order-fulfilment.d.ts +0 -142
- package/src/lib/plugin-manager/order-fulfilment.js +0 -104
- package/src/lib/plugin-manager/order-fulfilment.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/data-transfer/package.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*==========================================\n * PACKAGES — site items (pages, layouts, components, emails…) carried as one file.\n *\n * A package is a manifest and the items it lists. Each manifest entry\n * names the item's kind and id, its slug or name, a content hash, and the\n * items it depends on (a page on its layout, a layout on its components).\n *\n * ## Content hashes\n *\n * `sha256:` + the hex SHA-256 of the item's stable JSON — keys sorted at\n * every depth, `undefined` dropped — through WebCrypto, which both the\n * browser and Node provide. Equal hashes mean an import would change\n * nothing, so the item is `identical` and skipped by default.\n *\n * ## Importing an item\n *\n * Each item is matched to what the site already holds — by id, then slug,\n * then name, within its kind — and is `new`, `identical` or `differs`;\n * an item whose dependencies are neither in the package nor on the site is\n * flagged `missingDependency`. For a colliding item the person chooses:\n * replace it (as a new version), keep both (a new id and slug), skip it,\n * or merge it (for the kinds that merge key by key, like site settings).\n *=========================================*/\n\n/** The format tag every package carries. */\nexport const TRANSFER_PACKAGE_FORMAT = 'aglyn-package'\n\n/** The manifest version this module reads and writes. */\nexport const TRANSFER_PACKAGE_VERSION = 2\n\n/** An item another item needs. */\nexport interface PackageDependency {\n kind: string\n id: string\n}\n\n/** One item as the manifest lists it. */\nexport interface PackageManifestItem {\n kind: string\n $id: string\n slug?: string\n name?: string\n contentHash: string\n deps: PackageDependency[]\n}\n\nexport interface PackageManifest {\n format: typeof TRANSFER_PACKAGE_FORMAT\n version: typeof TRANSFER_PACKAGE_VERSION\n items: PackageManifestItem[]\n /** When the package was made (ms since epoch). */\n createdAt?: number\n /** Where it came from, for the import screen (\"Site: Acme\"). */\n source?: string\n}\n\n/** A whole package: the manifest and each item's content by {@link packageItemKey}. */\nexport interface TransferPackage<T = unknown> {\n manifest: PackageManifest\n items: Record<string, T>\n}\n\n/** The key an item is filed under: `<kind>/<id>`. */\nexport function packageItemKey(item: { kind: string; $id?: string; id?: string }): string {\n return `${item.kind}/${item.$id ?? item.id ?? ''}`\n}\n\n/**\n * JSON with every object's keys sorted, at every depth, and `undefined`\n * dropped (as `JSON.stringify` drops it). Dates are their ISO string;\n * a non-finite number is `null`. Two values that are the same data are\n * the same text, whatever order their keys were written in.\n */\nexport function stableJson(value: unknown): string {\n return JSON.stringify(canonical(value)) ?? 'null'\n}\n\nfunction canonical(value: unknown): unknown {\n if (value === null || value === undefined) return value\n if (value instanceof Date) return value.toISOString()\n if (typeof value === 'number') return Number.isFinite(value) ? value : null\n if (Array.isArray(value)) return value.map((entry) => (entry === undefined ? null : canonical(entry)))\n if (typeof value === 'object') {\n const source = value as Record<string, unknown>\n const sorted: Record<string, unknown> = {}\n for (const key of Object.keys(source).sort()) {\n if (source[key] === undefined) continue\n sorted[key] = canonical(source[key])\n }\n return sorted\n }\n return value\n}\n\n/** The hash prefix every content hash carries. */\nexport const CONTENT_HASH_PREFIX = 'sha256:'\n\n/**\n * The content hash of a value: `sha256:` + hex of its {@link stableJson}.\n * Uses WebCrypto (`globalThis.crypto.subtle`), present in browsers and Node.\n */\nexport async function contentHash(value: unknown): Promise<string> {\n const subtle = globalThis.crypto?.subtle\n if (!subtle) throw new Error('Content hashing needs WebCrypto (crypto.subtle).')\n const bytes = new TextEncoder().encode(stableJson(value))\n const digest = await subtle.digest('SHA-256', bytes)\n return CONTENT_HASH_PREFIX + [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join('')\n}\n\n/** A manifest read from a file, or why it cannot be. */\nexport type PackageManifestRead = { ok: true; manifest: PackageManifest } | { ok: false; problems: string[] }\n\n/**\n * A manifest from untrusted JSON. Every problem is reported, not just the\n * first: a wrong format or version, an item without a kind, id or hash, a\n * malformed dependency, an id listed twice.\n */\nexport function readPackageManifest(raw: unknown): PackageManifestRead {\n const problems: string[] = []\n if (!raw || typeof raw !== 'object') return { ok: false, problems: ['The file is not a package.'] }\n const source = raw as Record<string, unknown>\n if (source['format'] !== TRANSFER_PACKAGE_FORMAT) {\n problems.push(`The file's format is ${JSON.stringify(source['format'] ?? null)}, not \"${TRANSFER_PACKAGE_FORMAT}\".`)\n }\n if (source['version'] !== TRANSFER_PACKAGE_VERSION) {\n problems.push(`The package is version ${String(source['version'])}; this reads version ${TRANSFER_PACKAGE_VERSION}.`)\n }\n if (!Array.isArray(source['items'])) problems.push('The package lists no items.')\n const items: PackageManifestItem[] = []\n const seen = new Set<string>()\n for (const [index, entry] of (Array.isArray(source['items']) ? source['items'] : []).entries()) {\n const item = (entry ?? {}) as Record<string, unknown>\n const where = `Item ${index + 1}`\n const kind = typeof item['kind'] === 'string' ? item['kind'].trim() : ''\n const id = typeof item['$id'] === 'string' ? item['$id'].trim() : ''\n const hash = typeof item['contentHash'] === 'string' ? item['contentHash'] : ''\n if (!kind) problems.push(`${where} has no kind.`)\n if (!id) problems.push(`${where} has no id.`)\n if (!hash.startsWith(CONTENT_HASH_PREFIX)) problems.push(`${where} has no content hash.`)\n const deps: PackageDependency[] = []\n for (const dep of Array.isArray(item['deps']) ? item['deps'] : []) {\n const d = (dep ?? {}) as Record<string, unknown>\n if (typeof d['kind'] === 'string' && d['kind'] && typeof d['id'] === 'string' && d['id']) {\n deps.push({ kind: d['kind'], id: d['id'] })\n } else {\n problems.push(`${where} has a dependency without a kind and id.`)\n }\n }\n if (item['deps'] !== undefined && !Array.isArray(item['deps'])) problems.push(`${where} has dependencies that are not a list.`)\n const key = `${kind}/${id}`\n if (kind && id && seen.has(key)) problems.push(`${where} repeats ${key}.`)\n seen.add(key)\n items.push({\n kind,\n $id: id,\n ...(typeof item['slug'] === 'string' ? { slug: item['slug'] } : {}),\n ...(typeof item['name'] === 'string' ? { name: item['name'] } : {}),\n contentHash: hash,\n deps,\n })\n }\n if (problems.length) return { ok: false, problems }\n return {\n ok: true,\n manifest: {\n format: TRANSFER_PACKAGE_FORMAT,\n version: TRANSFER_PACKAGE_VERSION,\n items,\n ...(typeof source['createdAt'] === 'number' ? { createdAt: source['createdAt'] } : {}),\n ...(typeof source['source'] === 'string' ? { source: source['source'] } : {}),\n },\n }\n}\n\n/** A dependency that is not in the package (and, where asked, not on the site). */\nexport interface MissingPackageDependency {\n /** The item that needs it, by {@link packageItemKey}. */\n item: string\n dependency: PackageDependency\n}\n\n/** The items in an order that installs every dependency before what needs it. */\nexport interface PackageDependencyOrder {\n order: PackageManifestItem[]\n missing: MissingPackageDependency[]\n /** Each cycle as item keys; its items are appended to `order` in manifest order. */\n cycles: string[][]\n}\n\n/**\n * Dependencies first (Kahn's algorithm, ties in manifest order). A\n * dependency outside the package is reported as missing unless `available`\n * says the site has it. Items on a cycle cannot be ordered: each strongly\n * connected group is reported and its items appended last.\n */\nexport function packageDependencyOrder(\n items: readonly PackageManifestItem[],\n available: (dependency: PackageDependency) => boolean = () => false,\n): PackageDependencyOrder {\n const byKey = new Map(items.map((item) => [packageItemKey(item), item]))\n const missing: MissingPackageDependency[] = []\n const needs = new Map<string, Set<string>>()\n const neededBy = new Map<string, string[]>()\n for (const item of items) {\n const key = packageItemKey(item)\n const set = new Set<string>()\n for (const dep of item.deps) {\n const depKey = packageItemKey(dep)\n if (byKey.has(depKey)) {\n if (!set.has(depKey)) {\n set.add(depKey)\n neededBy.set(depKey, [...(neededBy.get(depKey) ?? []), key])\n }\n } else if (!available(dep)) {\n missing.push({ item: key, dependency: dep })\n }\n }\n needs.set(key, set)\n }\n const order: PackageManifestItem[] = []\n const placed = new Set<string>()\n const position = new Map(items.map((item, at) => [packageItemKey(item), at]))\n const byPosition = (a: string, b: string): number => (position.get(a) ?? 0) - (position.get(b) ?? 0)\n const ready = items.filter((item) => needs.get(packageItemKey(item))?.size === 0).map(packageItemKey)\n while (ready.length) {\n // Ties go in manifest order: the earliest ready item is placed next.\n ready.sort(byPosition)\n const key = ready.shift() as string\n if (placed.has(key)) continue\n placed.add(key)\n order.push(byKey.get(key) as PackageManifestItem)\n for (const dependent of neededBy.get(key) ?? []) {\n const set = needs.get(dependent) as Set<string>\n set.delete(key)\n if (set.size === 0) ready.push(dependent)\n }\n }\n const rest = items.filter((item) => !placed.has(packageItemKey(item)))\n const cycles = stronglyConnected(rest, byKey).filter(\n (group) => group.length > 1 || (byKey.get(group[0] as string)?.deps.some((dep) => packageItemKey(dep) === group[0]) ?? false),\n )\n return { order: [...order, ...rest], missing, cycles }\n}\n\n/** Tarjan's strongly connected components over the given items' in-package edges. */\nfunction stronglyConnected(\n items: readonly PackageManifestItem[],\n byKey: ReadonlyMap<string, PackageManifestItem>,\n): string[][] {\n const keys = new Set(items.map(packageItemKey))\n const index = new Map<string, number>()\n const low = new Map<string, number>()\n const stack: string[] = []\n const onStack = new Set<string>()\n const groups: string[][] = []\n let counter = 0\n const visit = (key: string): void => {\n index.set(key, counter)\n low.set(key, counter)\n counter += 1\n stack.push(key)\n onStack.add(key)\n for (const dep of byKey.get(key)?.deps ?? []) {\n const next = packageItemKey(dep)\n if (!keys.has(next)) continue\n if (!index.has(next)) {\n visit(next)\n low.set(key, Math.min(low.get(key) as number, low.get(next) as number))\n } else if (onStack.has(next)) {\n low.set(key, Math.min(low.get(key) as number, index.get(next) as number))\n }\n }\n if (low.get(key) === index.get(key)) {\n const group: string[] = []\n let member: string | undefined\n do {\n member = stack.pop() as string\n onStack.delete(member)\n group.push(member)\n } while (member !== key)\n groups.push(group.reverse())\n }\n }\n for (const key of keys) if (!index.has(key)) visit(key)\n return groups\n}\n\n/**\n * The selected items and everything they depend on inside the package,\n * transitively — the export picker's \"include dependencies\". Returns keys\n * in manifest order.\n */\nexport function packageDependencyClosure(\n items: readonly PackageManifestItem[],\n selected: Iterable<string>,\n): string[] {\n const byKey = new Map(items.map((item) => [packageItemKey(item), item]))\n const included = new Set<string>()\n const queue = [...selected].filter((key) => byKey.has(key))\n while (queue.length) {\n const key = queue.pop() as string\n if (included.has(key)) continue\n included.add(key)\n for (const dep of byKey.get(key)?.deps ?? []) {\n const depKey = packageItemKey(dep)\n if (byKey.has(depKey) && !included.has(depKey)) queue.push(depKey)\n }\n }\n return items.map(packageItemKey).filter((key) => included.has(key))\n}\n\n/** An item the site already holds. */\nexport interface ExistingPackageItem {\n kind: string\n id: string\n slug?: string\n name?: string\n contentHash: string\n}\n\n/** How an incoming item compares with what the site holds. */\nexport type PackageItemComparison = 'new' | 'identical' | 'differs'\n\n/** The status the import screen shows: the comparison, unless a dependency is missing. */\nexport type PackageItemStatus = PackageItemComparison | 'missingDependency'\n\nexport interface PackageItemMatch {\n item: PackageManifestItem\n status: PackageItemStatus\n comparison: PackageItemComparison\n existing?: ExistingPackageItem\n matchedBy?: 'id' | 'slug' | 'name'\n /** Dependencies neither in the package nor on the site. */\n missing: PackageDependency[]\n}\n\nfunction caseless(value: string | undefined): string {\n return String(value ?? '').trim().toLowerCase()\n}\n\n/**\n * Every manifest item against what the site holds: matched by id, then\n * slug, then name, within its kind; compared by content hash; and checked\n * for dependencies that exist in neither place.\n */\nexport function matchPackageItems(\n manifest: Pick<PackageManifest, 'items'>,\n existing: readonly ExistingPackageItem[],\n): PackageItemMatch[] {\n const inPackage = new Set(manifest.items.map(packageItemKey))\n const onSite = new Set(existing.map((item) => `${item.kind}/${item.id}`))\n return manifest.items.map((item) => {\n const sameKind = existing.filter((entry) => entry.kind === item.kind)\n let found: ExistingPackageItem | undefined = sameKind.find((entry) => entry.id === item.$id)\n let matchedBy: PackageItemMatch['matchedBy'] = found ? 'id' : undefined\n if (!found && item.slug) {\n found = sameKind.find((entry) => entry.slug && caseless(entry.slug) === caseless(item.slug))\n if (found) matchedBy = 'slug'\n }\n if (!found && item.name) {\n found = sameKind.find((entry) => entry.name && caseless(entry.name) === caseless(item.name))\n if (found) matchedBy = 'name'\n }\n const comparison: PackageItemComparison = !found ? 'new' : found.contentHash === item.contentHash ? 'identical' : 'differs'\n const missing = item.deps.filter((dep) => {\n const key = packageItemKey(dep)\n return !inPackage.has(key) && !onSite.has(key)\n })\n return {\n item,\n status: missing.length ? 'missingDependency' : comparison,\n comparison,\n ...(found ? { existing: found, matchedBy } : {}),\n missing,\n }\n })\n}\n\n/** What to do with an incoming item that collides with one the site holds. */\nexport type PackageCollisionChoice = 'replace' | 'keepBoth' | 'skip' | 'merge'\n\n/** What to do with an item: create it (new), or a collision choice. */\nexport type PackageItemDecision = 'create' | PackageCollisionChoice\n\n/** What to do about a dependency the package and the site both lack. */\nexport type PackageMissingDependencyChoice =\n | { action: 'mapTo'; id: string }\n | { action: 'dropReference' }\n | { action: 'skipItem' }\n\n/**\n * The decision proposed before the person chooses: create a new item, skip\n * an identical one, and skip a differing one — replacing is never assumed;\n * `needsChoice` marks the items the person must decide.\n */\nexport function proposePackageDecision(match: PackageItemMatch): { decision: PackageItemDecision; needsChoice: boolean } {\n if (match.comparison === 'new') return { decision: 'create', needsChoice: match.missing.length > 0 }\n if (match.comparison === 'identical') return { decision: 'skip', needsChoice: match.missing.length > 0 }\n return { decision: 'skip', needsChoice: true }\n}\n\n/** The decisions an item may take; `merge` only for kinds that merge key by key. */\nexport function packageDecisionsFor(match: PackageItemMatch, mergeable = false): PackageItemDecision[] {\n if (match.comparison === 'new') return ['create', 'skip']\n return mergeable ? ['replace', 'keepBoth', 'skip', 'merge'] : ['replace', 'keepBoth', 'skip']\n}\n\n/**\n * The slug a kept-both copy takes: `<slug>-copy`, then `-copy-2`, `-copy-3`…\n * until none of `taken` (compared caselessly).\n */\nexport function keepBothSlug(slug: string, taken: Iterable<string>): string {\n const used = new Set([...taken].map(caseless))\n const base = `${slug.replace(/-copy(?:-\\d+)?$/, '')}-copy`\n if (!used.has(caseless(base))) return base\n for (let n = 2; ; n += 1) {\n const candidate = `${base}-${n}`\n if (!used.has(caseless(candidate))) return candidate\n }\n}\n\n/**\n * The manifest for a set of items. Hashes each item's content; `deps` and\n * the slug and name come from `describe`. Items are listed in the order given.\n */\nexport async function buildPackageManifest<T>(\n items: readonly { kind: string; id: string; content: T }[],\n describe: (item: { kind: string; id: string; content: T }) => {\n slug?: string\n name?: string\n deps?: PackageDependency[]\n } = () => ({}),\n meta: Pick<PackageManifest, 'createdAt' | 'source'> = {},\n): Promise<TransferPackage<T>> {\n const entries: PackageManifestItem[] = []\n const contents: Record<string, T> = {}\n for (const item of items) {\n const described = describe(item)\n const entry: PackageManifestItem = {\n kind: item.kind,\n $id: item.id,\n ...(described.slug ? { slug: described.slug } : {}),\n ...(described.name ? { name: described.name } : {}),\n contentHash: await contentHash(item.content),\n deps: described.deps ?? [],\n }\n entries.push(entry)\n contents[packageItemKey(entry)] = item.content\n }\n return {\n manifest: { format: TRANSFER_PACKAGE_FORMAT, version: TRANSFER_PACKAGE_VERSION, items: entries, ...meta },\n items: contents,\n }\n}\n"],"names":["TRANSFER_PACKAGE_FORMAT","TRANSFER_PACKAGE_VERSION","packageItemKey","item","kind","$id","id","stableJson","value","JSON","stringify","canonical","undefined","Date","toISOString","Number","isFinite","Array","isArray","map","entry","source","sorted","key","Object","keys","sort","CONTENT_HASH_PREFIX","contentHash","globalThis","subtle","crypto","Error","bytes","TextEncoder","encode","digest","Uint8Array","byte","toString","padStart","join","readPackageManifest","raw","problems","ok","push","String","items","seen","Set","index","entries","where","trim","hash","startsWith","deps","dep","d","has","add","slug","name","length","manifest","format","version","createdAt","packageDependencyOrder","available","byKey","Map","missing","needs","neededBy","set","depKey","get","dependency","order","placed","position","at","byPosition","a","b","ready","filter","size","shift","dependent","delete","rest","cycles","stronglyConnected","group","some","low","stack","onStack","groups","counter","visit","next","Math","min","member","pop","reverse","packageDependencyClosure","selected","included","queue","caseless","toLowerCase","matchPackageItems","existing","inPackage","onSite","sameKind","found","find","matchedBy","comparison","status","proposePackageDecision","match","decision","needsChoice","packageDecisionsFor","mergeable","keepBothSlug","taken","used","base","replace","n","candidate","buildPackageManifest","describe","meta","contents","described","content"],"mappings":"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"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import type { PicklistSpec, PicklistValue, PicklistValueSet } from '../app-utils/picklists';
|
|
18
|
+
/** One distinct value of a column, with where it occurs. */
|
|
19
|
+
export interface PicklistIncomingValue {
|
|
20
|
+
/** The first spelling the file used. */
|
|
21
|
+
value: string;
|
|
22
|
+
/** The comparison key ({@link picklistLabelKey}). */
|
|
23
|
+
key: string;
|
|
24
|
+
/** How many cells carry it. */
|
|
25
|
+
count: number;
|
|
26
|
+
/** The first few row indexes that carry it. */
|
|
27
|
+
rows: number[];
|
|
28
|
+
}
|
|
29
|
+
/** How many row indexes a distinct value keeps as samples. */
|
|
30
|
+
export declare const PICKLIST_SAMPLE_ROWS = 5;
|
|
31
|
+
/**
|
|
32
|
+
* The distinct values of a column, in the order first seen. A multi-value
|
|
33
|
+
* cell (an array) counts each of its values.
|
|
34
|
+
*/
|
|
35
|
+
export declare function collectPicklistValues(cells: Iterable<{
|
|
36
|
+
row: number;
|
|
37
|
+
value: unknown;
|
|
38
|
+
}>): PicklistIncomingValue[];
|
|
39
|
+
/** A value of the list an incoming value might have meant. */
|
|
40
|
+
export interface PicklistSuggestion {
|
|
41
|
+
valueId: string;
|
|
42
|
+
label: string;
|
|
43
|
+
confidence: number;
|
|
44
|
+
}
|
|
45
|
+
/** An incoming value the list holds. */
|
|
46
|
+
export interface PicklistMatched extends PicklistIncomingValue {
|
|
47
|
+
valueId: string;
|
|
48
|
+
/** The label as the list spells it — what records store. */
|
|
49
|
+
label: string;
|
|
50
|
+
/** The list holds it deactivated; storing it is allowed but worth a word. */
|
|
51
|
+
inactive: boolean;
|
|
52
|
+
/** Matched by value id rather than by label. */
|
|
53
|
+
byId: boolean;
|
|
54
|
+
}
|
|
55
|
+
/** An incoming value the list does not hold. */
|
|
56
|
+
export interface PicklistUnmatched extends PicklistIncomingValue {
|
|
57
|
+
/** The list's values it is closest to, strongest first. */
|
|
58
|
+
suggestions: PicklistSuggestion[];
|
|
59
|
+
}
|
|
60
|
+
export interface PicklistMatchResult {
|
|
61
|
+
matched: PicklistMatched[];
|
|
62
|
+
unmatched: PicklistUnmatched[];
|
|
63
|
+
}
|
|
64
|
+
/** The least similarity a suggestion is offered at. */
|
|
65
|
+
export declare const PICKLIST_SUGGESTION_THRESHOLD = 0.6;
|
|
66
|
+
/**
|
|
67
|
+
* The incoming values against the organization's effective list. A value
|
|
68
|
+
* matches a list value by label (any case or spacing) or by id; the rest
|
|
69
|
+
* are unmatched, each with the closest list values as suggestions.
|
|
70
|
+
*/
|
|
71
|
+
export declare function matchPicklistValues(set: PicklistValueSet, incoming: readonly PicklistIncomingValue[]): PicklistMatchResult;
|
|
72
|
+
/** What to do with one unmatched value. */
|
|
73
|
+
export type PicklistValueChoice = {
|
|
74
|
+
action: 'mapTo';
|
|
75
|
+
valueId: string;
|
|
76
|
+
} | {
|
|
77
|
+
action: 'addValue';
|
|
78
|
+
label?: string;
|
|
79
|
+
group?: string | null;
|
|
80
|
+
meaning?: string | null;
|
|
81
|
+
} | {
|
|
82
|
+
action: 'leaveBlank';
|
|
83
|
+
} | {
|
|
84
|
+
action: 'refuseRow';
|
|
85
|
+
};
|
|
86
|
+
/** The suggestion confidence at which "map to it" is proposed outright. */
|
|
87
|
+
export declare const PICKLIST_AUTO_MAP_CONFIDENCE = 0.9;
|
|
88
|
+
/**
|
|
89
|
+
* The choice proposed before the person decides: map to a near-certain
|
|
90
|
+
* suggestion; else add the value to an open list (an unrestricted one with
|
|
91
|
+
* no meanings, which would store it as typed anyway); else leave it blank.
|
|
92
|
+
* Every proposal is shown and can be changed — none is applied unseen.
|
|
93
|
+
*/
|
|
94
|
+
export declare function proposePicklistChoice(spec: PicklistSpec, value: PicklistUnmatched): PicklistValueChoice;
|
|
95
|
+
/**
|
|
96
|
+
* What is wrong with a set of choices, as sentences: a value with no
|
|
97
|
+
* choice, a mapping to a value the list does not hold, an added value that
|
|
98
|
+
* needs a meaning or names an unknown group or meaning, two added values
|
|
99
|
+
* with one label, or more values than a list may hold.
|
|
100
|
+
*/
|
|
101
|
+
export declare function picklistChoiceProblems(spec: PicklistSpec, set: PicklistValueSet, unmatched: readonly PicklistUnmatched[], choices: Readonly<Record<string, PicklistValueChoice | undefined>>): string[];
|
|
102
|
+
/** What one incoming value becomes. */
|
|
103
|
+
export type PicklistCellOutcome = {
|
|
104
|
+
kind: 'value';
|
|
105
|
+
label: string;
|
|
106
|
+
valueId: string;
|
|
107
|
+
} | {
|
|
108
|
+
kind: 'blank';
|
|
109
|
+
} | {
|
|
110
|
+
kind: 'refuse';
|
|
111
|
+
};
|
|
112
|
+
/** The choices applied: the list with added values, and how each incoming value resolves. */
|
|
113
|
+
export interface PicklistResolution {
|
|
114
|
+
/** The list with every added value appended, active. */
|
|
115
|
+
set: PicklistValueSet;
|
|
116
|
+
/** The values to add to the organization's list. */
|
|
117
|
+
added: PicklistValue[];
|
|
118
|
+
/** Incoming key → outcome, for matched and unmatched values alike. */
|
|
119
|
+
outcomes: Map<string, PicklistCellOutcome>;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* The choices applied to the list. Matched values resolve to the list's
|
|
123
|
+
* own label; added values are minted ids that never collide with a stored
|
|
124
|
+
* or standard id. A value with no choice resolves to blank — callers check
|
|
125
|
+
* {@link picklistChoiceProblems} first.
|
|
126
|
+
*/
|
|
127
|
+
export declare function resolvePicklistChoices(spec: PicklistSpec, set: PicklistValueSet, result: PicklistMatchResult, choices: Readonly<Record<string, PicklistValueChoice | undefined>>): PicklistResolution;
|
|
128
|
+
/** One cell through a resolution: the label to store, blank, or refuse the row. */
|
|
129
|
+
export declare function resolvePicklistCell(resolution: PicklistResolution, raw: unknown): PicklistCellOutcome;
|
|
130
|
+
/**
|
|
131
|
+
* A multi-value cell through a resolution: the labels to store, in order and
|
|
132
|
+
* without repeats; `refuse` when any value refuses the row.
|
|
133
|
+
*/
|
|
134
|
+
export declare function resolveMultiPicklistCell(resolution: PicklistResolution, raw: readonly unknown[]): {
|
|
135
|
+
kind: 'values';
|
|
136
|
+
labels: string[];
|
|
137
|
+
} | {
|
|
138
|
+
kind: 'refuse';
|
|
139
|
+
};
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ /*==========================================
|
|
18
|
+
* PICKLIST MAPPING — what to do with a file's values a picklist does not hold.
|
|
19
|
+
*
|
|
20
|
+
* For each picklist column the wizard lists the DISTINCT values the file
|
|
21
|
+
* carries. A value the organization's list already holds (by label in any
|
|
22
|
+
* case or spacing, or by value id) is matched. Every other value gets a
|
|
23
|
+
* choice, made once and applied to every row that carries it:
|
|
24
|
+
*
|
|
25
|
+
* - map it to an existing value;
|
|
26
|
+
* - add it to the organization's list as a new value (with a group, and a
|
|
27
|
+
* meaning when the list needs one);
|
|
28
|
+
* - leave the field blank on those rows;
|
|
29
|
+
* - refuse those rows.
|
|
30
|
+
*
|
|
31
|
+
* Built on the picklist engine (`app-utils/picklists.ts`): labels compare
|
|
32
|
+
* by its key, new value ids are minted by it, and an added value can never
|
|
33
|
+
* take a standard value's id.
|
|
34
|
+
*=========================================*/ import { PICKLIST_VALUES_MAX, mintPicklistValueId, normalizePicklistLabel, picklistLabelKey, picklistValueByLabel } from "../app-utils/picklists.js";
|
|
35
|
+
import { textSimilarity } from "./similarity.js";
|
|
36
|
+
/** How many row indexes a distinct value keeps as samples. */ export const PICKLIST_SAMPLE_ROWS = 5;
|
|
37
|
+
/**
|
|
38
|
+
* The distinct values of a column, in the order first seen. A multi-value
|
|
39
|
+
* cell (an array) counts each of its values.
|
|
40
|
+
*/ export function collectPicklistValues(cells) {
|
|
41
|
+
const byKey = new Map();
|
|
42
|
+
for (const { row, value } of cells){
|
|
43
|
+
const values = Array.isArray(value) ? value : [
|
|
44
|
+
value
|
|
45
|
+
];
|
|
46
|
+
for (const entry of values){
|
|
47
|
+
const label = normalizePicklistLabel(entry);
|
|
48
|
+
if (!label) continue;
|
|
49
|
+
const key = picklistLabelKey(label);
|
|
50
|
+
const seen = byKey.get(key);
|
|
51
|
+
if (seen) {
|
|
52
|
+
seen.count += 1;
|
|
53
|
+
if (seen.rows.length < PICKLIST_SAMPLE_ROWS && !seen.rows.includes(row)) seen.rows.push(row);
|
|
54
|
+
} else {
|
|
55
|
+
byKey.set(key, {
|
|
56
|
+
value: label,
|
|
57
|
+
key,
|
|
58
|
+
count: 1,
|
|
59
|
+
rows: [
|
|
60
|
+
row
|
|
61
|
+
]
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return [
|
|
67
|
+
...byKey.values()
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
/** The least similarity a suggestion is offered at. */ export const PICKLIST_SUGGESTION_THRESHOLD = 0.6;
|
|
71
|
+
/**
|
|
72
|
+
* The incoming values against the organization's effective list. A value
|
|
73
|
+
* matches a list value by label (any case or spacing) or by id; the rest
|
|
74
|
+
* are unmatched, each with the closest list values as suggestions.
|
|
75
|
+
*/ export function matchPicklistValues(set, incoming) {
|
|
76
|
+
const matched = [];
|
|
77
|
+
const unmatched = [];
|
|
78
|
+
for (const value of incoming){
|
|
79
|
+
var _ref;
|
|
80
|
+
const byLabel = picklistValueByLabel(set, value.value);
|
|
81
|
+
const byId = (_ref = byLabel != null ? byLabel : set.values.find((entry)=>entry.id.toLowerCase() === value.value.toLowerCase())) != null ? _ref : null;
|
|
82
|
+
if (byId) {
|
|
83
|
+
matched.push(_extends({}, value, {
|
|
84
|
+
valueId: byId.id,
|
|
85
|
+
label: byId.label,
|
|
86
|
+
inactive: !byId.active,
|
|
87
|
+
byId: !byLabel
|
|
88
|
+
}));
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const suggestions = set.values.filter((entry)=>entry.active).map((entry)=>({
|
|
92
|
+
valueId: entry.id,
|
|
93
|
+
label: entry.label,
|
|
94
|
+
confidence: Math.round(textSimilarity(value.value, entry.label) * 1000) / 1000
|
|
95
|
+
})).filter((entry)=>entry.confidence >= PICKLIST_SUGGESTION_THRESHOLD).sort((a, b)=>b.confidence - a.confidence).slice(0, 3);
|
|
96
|
+
unmatched.push(_extends({}, value, {
|
|
97
|
+
suggestions
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
matched,
|
|
102
|
+
unmatched
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** The suggestion confidence at which "map to it" is proposed outright. */ export const PICKLIST_AUTO_MAP_CONFIDENCE = 0.9;
|
|
106
|
+
/**
|
|
107
|
+
* The choice proposed before the person decides: map to a near-certain
|
|
108
|
+
* suggestion; else add the value to an open list (an unrestricted one with
|
|
109
|
+
* no meanings, which would store it as typed anyway); else leave it blank.
|
|
110
|
+
* Every proposal is shown and can be changed — none is applied unseen.
|
|
111
|
+
*/ export function proposePicklistChoice(spec, value) {
|
|
112
|
+
var _spec_meanings;
|
|
113
|
+
const top = value.suggestions[0];
|
|
114
|
+
if (top && top.confidence >= PICKLIST_AUTO_MAP_CONFIDENCE) return {
|
|
115
|
+
action: 'mapTo',
|
|
116
|
+
valueId: top.valueId
|
|
117
|
+
};
|
|
118
|
+
if (!spec.restricted && !((_spec_meanings = spec.meanings) == null ? void 0 : _spec_meanings.length)) return {
|
|
119
|
+
action: 'addValue'
|
|
120
|
+
};
|
|
121
|
+
return {
|
|
122
|
+
action: 'leaveBlank'
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* What is wrong with a set of choices, as sentences: a value with no
|
|
127
|
+
* choice, a mapping to a value the list does not hold, an added value that
|
|
128
|
+
* needs a meaning or names an unknown group or meaning, two added values
|
|
129
|
+
* with one label, or more values than a list may hold.
|
|
130
|
+
*/ export function picklistChoiceProblems(spec, set, unmatched, choices) {
|
|
131
|
+
const problems = [];
|
|
132
|
+
const labels = new Set(set.values.map((value)=>picklistLabelKey(value.label)));
|
|
133
|
+
let added = 0;
|
|
134
|
+
for (const value of unmatched){
|
|
135
|
+
var _choice_label;
|
|
136
|
+
var _spec_meanings, _spec_groups;
|
|
137
|
+
const choice = choices[value.key];
|
|
138
|
+
if (!choice) {
|
|
139
|
+
problems.push(`Choose what to do with "${value.value}".`);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (choice.action === 'mapTo' && !set.values.some((entry)=>entry.id === choice.valueId)) {
|
|
143
|
+
problems.push(`"${value.value}" is mapped to a value the list does not hold.`);
|
|
144
|
+
}
|
|
145
|
+
if (choice.action !== 'addValue') continue;
|
|
146
|
+
added += 1;
|
|
147
|
+
const label = normalizePicklistLabel((_choice_label = choice.label) != null ? _choice_label : value.value);
|
|
148
|
+
if (!label) problems.push(`"${value.value}" needs a label to be added.`);
|
|
149
|
+
else if (labels.has(picklistLabelKey(label))) problems.push(`"${label}" is already in the list or added twice.`);
|
|
150
|
+
labels.add(picklistLabelKey(label));
|
|
151
|
+
if ((_spec_meanings = spec.meanings) == null ? void 0 : _spec_meanings.length) {
|
|
152
|
+
if (!choice.meaning) problems.push(`"${label}" needs a meaning to be added.`);
|
|
153
|
+
else if (!spec.meanings.includes(choice.meaning)) problems.push(`"${label}" names an unknown meaning.`);
|
|
154
|
+
}
|
|
155
|
+
if (choice.group && !((_spec_groups = spec.groups) == null ? void 0 : _spec_groups.some((group)=>group.id === choice.group))) {
|
|
156
|
+
problems.push(`"${label}" names an unknown group.`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (set.values.length + added > PICKLIST_VALUES_MAX) {
|
|
160
|
+
problems.push(`A list holds at most ${PICKLIST_VALUES_MAX} values; this would make ${set.values.length + added}.`);
|
|
161
|
+
}
|
|
162
|
+
return problems;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* The choices applied to the list. Matched values resolve to the list's
|
|
166
|
+
* own label; added values are minted ids that never collide with a stored
|
|
167
|
+
* or standard id. A value with no choice resolves to blank — callers check
|
|
168
|
+
* {@link picklistChoiceProblems} first.
|
|
169
|
+
*/ export function resolvePicklistChoices(spec, set, result, choices) {
|
|
170
|
+
const values = set.values.map((value)=>_extends({}, value));
|
|
171
|
+
const added = [];
|
|
172
|
+
const outcomes = new Map();
|
|
173
|
+
for (const value of result.matched){
|
|
174
|
+
outcomes.set(value.key, {
|
|
175
|
+
kind: 'value',
|
|
176
|
+
label: value.label,
|
|
177
|
+
valueId: value.valueId
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
const taken = ()=>[
|
|
181
|
+
...values.map((value)=>value.id),
|
|
182
|
+
...spec.standardValues.map((value)=>value.id)
|
|
183
|
+
];
|
|
184
|
+
for (const value of result.unmatched){
|
|
185
|
+
const choice = choices[value.key];
|
|
186
|
+
if ((choice == null ? void 0 : choice.action) === 'mapTo') {
|
|
187
|
+
const target = values.find((entry)=>entry.id === choice.valueId);
|
|
188
|
+
outcomes.set(value.key, target ? {
|
|
189
|
+
kind: 'value',
|
|
190
|
+
label: target.label,
|
|
191
|
+
valueId: target.id
|
|
192
|
+
} : {
|
|
193
|
+
kind: 'blank'
|
|
194
|
+
});
|
|
195
|
+
} else if ((choice == null ? void 0 : choice.action) === 'addValue') {
|
|
196
|
+
var _choice_label, _choice_group, _choice_meaning;
|
|
197
|
+
var _spec_groups, _spec_meanings;
|
|
198
|
+
const label = normalizePicklistLabel((_choice_label = choice.label) != null ? _choice_label : value.value);
|
|
199
|
+
const existing = values.find((entry)=>picklistLabelKey(entry.label) === picklistLabelKey(label));
|
|
200
|
+
if (existing) {
|
|
201
|
+
outcomes.set(value.key, {
|
|
202
|
+
kind: 'value',
|
|
203
|
+
label: existing.label,
|
|
204
|
+
valueId: existing.id
|
|
205
|
+
});
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
const entry = _extends({
|
|
209
|
+
id: mintPicklistValueId(label, taken()),
|
|
210
|
+
label,
|
|
211
|
+
active: true
|
|
212
|
+
}, ((_spec_groups = spec.groups) == null ? void 0 : _spec_groups.length) ? {
|
|
213
|
+
group: (_choice_group = choice.group) != null ? _choice_group : null
|
|
214
|
+
} : {}, ((_spec_meanings = spec.meanings) == null ? void 0 : _spec_meanings.length) ? {
|
|
215
|
+
meaning: (_choice_meaning = choice.meaning) != null ? _choice_meaning : null
|
|
216
|
+
} : {});
|
|
217
|
+
values.push(entry);
|
|
218
|
+
added.push(entry);
|
|
219
|
+
outcomes.set(value.key, {
|
|
220
|
+
kind: 'value',
|
|
221
|
+
label: entry.label,
|
|
222
|
+
valueId: entry.id
|
|
223
|
+
});
|
|
224
|
+
} else if ((choice == null ? void 0 : choice.action) === 'refuseRow') {
|
|
225
|
+
outcomes.set(value.key, {
|
|
226
|
+
kind: 'refuse'
|
|
227
|
+
});
|
|
228
|
+
} else {
|
|
229
|
+
outcomes.set(value.key, {
|
|
230
|
+
kind: 'blank'
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
set: {
|
|
236
|
+
values,
|
|
237
|
+
defaultValueId: set.defaultValueId
|
|
238
|
+
},
|
|
239
|
+
added,
|
|
240
|
+
outcomes
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/** One cell through a resolution: the label to store, blank, or refuse the row. */ export function resolvePicklistCell(resolution, raw) {
|
|
244
|
+
var _resolution_outcomes_get;
|
|
245
|
+
const label = normalizePicklistLabel(raw);
|
|
246
|
+
if (!label) return {
|
|
247
|
+
kind: 'blank'
|
|
248
|
+
};
|
|
249
|
+
return (_resolution_outcomes_get = resolution.outcomes.get(picklistLabelKey(label))) != null ? _resolution_outcomes_get : {
|
|
250
|
+
kind: 'blank'
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* A multi-value cell through a resolution: the labels to store, in order and
|
|
255
|
+
* without repeats; `refuse` when any value refuses the row.
|
|
256
|
+
*/ export function resolveMultiPicklistCell(resolution, raw) {
|
|
257
|
+
const labels = [];
|
|
258
|
+
for (const entry of raw){
|
|
259
|
+
const outcome = resolvePicklistCell(resolution, entry);
|
|
260
|
+
if (outcome.kind === 'refuse') return {
|
|
261
|
+
kind: 'refuse'
|
|
262
|
+
};
|
|
263
|
+
if (outcome.kind === 'value' && !labels.includes(outcome.label)) labels.push(outcome.label);
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
kind: 'values',
|
|
267
|
+
labels
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
//# sourceMappingURL=picklist-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/data-transfer/picklist-map.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*==========================================\n * PICKLIST MAPPING — what to do with a file's values a picklist does not hold.\n *\n * For each picklist column the wizard lists the DISTINCT values the file\n * carries. A value the organization's list already holds (by label in any\n * case or spacing, or by value id) is matched. Every other value gets a\n * choice, made once and applied to every row that carries it:\n *\n * - map it to an existing value;\n * - add it to the organization's list as a new value (with a group, and a\n * meaning when the list needs one);\n * - leave the field blank on those rows;\n * - refuse those rows.\n *\n * Built on the picklist engine (`app-utils/picklists.ts`): labels compare\n * by its key, new value ids are minted by it, and an added value can never\n * take a standard value's id.\n *=========================================*/\n\nimport {\n PICKLIST_VALUES_MAX,\n mintPicklistValueId,\n normalizePicklistLabel,\n picklistLabelKey,\n picklistValueByLabel,\n} from '../app-utils/picklists'\nimport type { PicklistSpec, PicklistValue, PicklistValueSet } from '../app-utils/picklists'\nimport { textSimilarity } from './similarity'\n\n/** One distinct value of a column, with where it occurs. */\nexport interface PicklistIncomingValue {\n /** The first spelling the file used. */\n value: string\n /** The comparison key ({@link picklistLabelKey}). */\n key: string\n /** How many cells carry it. */\n count: number\n /** The first few row indexes that carry it. */\n rows: number[]\n}\n\n/** How many row indexes a distinct value keeps as samples. */\nexport const PICKLIST_SAMPLE_ROWS = 5\n\n/**\n * The distinct values of a column, in the order first seen. A multi-value\n * cell (an array) counts each of its values.\n */\nexport function collectPicklistValues(\n cells: Iterable<{ row: number; value: unknown }>,\n): PicklistIncomingValue[] {\n const byKey = new Map<string, PicklistIncomingValue>()\n for (const { row, value } of cells) {\n const values = Array.isArray(value) ? value : [value]\n for (const entry of values) {\n const label = normalizePicklistLabel(entry)\n if (!label) continue\n const key = picklistLabelKey(label)\n const seen = byKey.get(key)\n if (seen) {\n seen.count += 1\n if (seen.rows.length < PICKLIST_SAMPLE_ROWS && !seen.rows.includes(row)) seen.rows.push(row)\n } else {\n byKey.set(key, { value: label, key, count: 1, rows: [row] })\n }\n }\n }\n return [...byKey.values()]\n}\n\n/** A value of the list an incoming value might have meant. */\nexport interface PicklistSuggestion {\n valueId: string\n label: string\n confidence: number\n}\n\n/** An incoming value the list holds. */\nexport interface PicklistMatched extends PicklistIncomingValue {\n valueId: string\n /** The label as the list spells it — what records store. */\n label: string\n /** The list holds it deactivated; storing it is allowed but worth a word. */\n inactive: boolean\n /** Matched by value id rather than by label. */\n byId: boolean\n}\n\n/** An incoming value the list does not hold. */\nexport interface PicklistUnmatched extends PicklistIncomingValue {\n /** The list's values it is closest to, strongest first. */\n suggestions: PicklistSuggestion[]\n}\n\nexport interface PicklistMatchResult {\n matched: PicklistMatched[]\n unmatched: PicklistUnmatched[]\n}\n\n/** The least similarity a suggestion is offered at. */\nexport const PICKLIST_SUGGESTION_THRESHOLD = 0.6\n\n/**\n * The incoming values against the organization's effective list. A value\n * matches a list value by label (any case or spacing) or by id; the rest\n * are unmatched, each with the closest list values as suggestions.\n */\nexport function matchPicklistValues(\n set: PicklistValueSet,\n incoming: readonly PicklistIncomingValue[],\n): PicklistMatchResult {\n const matched: PicklistMatched[] = []\n const unmatched: PicklistUnmatched[] = []\n for (const value of incoming) {\n const byLabel = picklistValueByLabel(set, value.value)\n const byId =\n byLabel ?? set.values.find((entry) => entry.id.toLowerCase() === value.value.toLowerCase()) ?? null\n if (byId) {\n matched.push({ ...value, valueId: byId.id, label: byId.label, inactive: !byId.active, byId: !byLabel })\n continue\n }\n const suggestions = set.values\n .filter((entry) => entry.active)\n .map((entry) => ({\n valueId: entry.id,\n label: entry.label,\n confidence: Math.round(textSimilarity(value.value, entry.label) * 1000) / 1000,\n }))\n .filter((entry) => entry.confidence >= PICKLIST_SUGGESTION_THRESHOLD)\n .sort((a, b) => b.confidence - a.confidence)\n .slice(0, 3)\n unmatched.push({ ...value, suggestions })\n }\n return { matched, unmatched }\n}\n\n/** What to do with one unmatched value. */\nexport type PicklistValueChoice =\n | { action: 'mapTo'; valueId: string }\n | { action: 'addValue'; label?: string; group?: string | null; meaning?: string | null }\n | { action: 'leaveBlank' }\n | { action: 'refuseRow' }\n\n/** The suggestion confidence at which \"map to it\" is proposed outright. */\nexport const PICKLIST_AUTO_MAP_CONFIDENCE = 0.9\n\n/**\n * The choice proposed before the person decides: map to a near-certain\n * suggestion; else add the value to an open list (an unrestricted one with\n * no meanings, which would store it as typed anyway); else leave it blank.\n * Every proposal is shown and can be changed — none is applied unseen.\n */\nexport function proposePicklistChoice(spec: PicklistSpec, value: PicklistUnmatched): PicklistValueChoice {\n const top = value.suggestions[0]\n if (top && top.confidence >= PICKLIST_AUTO_MAP_CONFIDENCE) return { action: 'mapTo', valueId: top.valueId }\n if (!spec.restricted && !spec.meanings?.length) return { action: 'addValue' }\n return { action: 'leaveBlank' }\n}\n\n/**\n * What is wrong with a set of choices, as sentences: a value with no\n * choice, a mapping to a value the list does not hold, an added value that\n * needs a meaning or names an unknown group or meaning, two added values\n * with one label, or more values than a list may hold.\n */\nexport function picklistChoiceProblems(\n spec: PicklistSpec,\n set: PicklistValueSet,\n unmatched: readonly PicklistUnmatched[],\n choices: Readonly<Record<string, PicklistValueChoice | undefined>>,\n): string[] {\n const problems: string[] = []\n const labels = new Set(set.values.map((value) => picklistLabelKey(value.label)))\n let added = 0\n for (const value of unmatched) {\n const choice = choices[value.key]\n if (!choice) {\n problems.push(`Choose what to do with \"${value.value}\".`)\n continue\n }\n if (choice.action === 'mapTo' && !set.values.some((entry) => entry.id === choice.valueId)) {\n problems.push(`\"${value.value}\" is mapped to a value the list does not hold.`)\n }\n if (choice.action !== 'addValue') continue\n added += 1\n const label = normalizePicklistLabel(choice.label ?? value.value)\n if (!label) problems.push(`\"${value.value}\" needs a label to be added.`)\n else if (labels.has(picklistLabelKey(label))) problems.push(`\"${label}\" is already in the list or added twice.`)\n labels.add(picklistLabelKey(label))\n if (spec.meanings?.length) {\n if (!choice.meaning) problems.push(`\"${label}\" needs a meaning to be added.`)\n else if (!spec.meanings.includes(choice.meaning)) problems.push(`\"${label}\" names an unknown meaning.`)\n }\n if (choice.group && !spec.groups?.some((group) => group.id === choice.group)) {\n problems.push(`\"${label}\" names an unknown group.`)\n }\n }\n if (set.values.length + added > PICKLIST_VALUES_MAX) {\n problems.push(`A list holds at most ${PICKLIST_VALUES_MAX} values; this would make ${set.values.length + added}.`)\n }\n return problems\n}\n\n/** What one incoming value becomes. */\nexport type PicklistCellOutcome =\n | { kind: 'value'; label: string; valueId: string }\n | { kind: 'blank' }\n | { kind: 'refuse' }\n\n/** The choices applied: the list with added values, and how each incoming value resolves. */\nexport interface PicklistResolution {\n /** The list with every added value appended, active. */\n set: PicklistValueSet\n /** The values to add to the organization's list. */\n added: PicklistValue[]\n /** Incoming key → outcome, for matched and unmatched values alike. */\n outcomes: Map<string, PicklistCellOutcome>\n}\n\n/**\n * The choices applied to the list. Matched values resolve to the list's\n * own label; added values are minted ids that never collide with a stored\n * or standard id. A value with no choice resolves to blank — callers check\n * {@link picklistChoiceProblems} first.\n */\nexport function resolvePicklistChoices(\n spec: PicklistSpec,\n set: PicklistValueSet,\n result: PicklistMatchResult,\n choices: Readonly<Record<string, PicklistValueChoice | undefined>>,\n): PicklistResolution {\n const values = set.values.map((value) => ({ ...value }))\n const added: PicklistValue[] = []\n const outcomes = new Map<string, PicklistCellOutcome>()\n for (const value of result.matched) {\n outcomes.set(value.key, { kind: 'value', label: value.label, valueId: value.valueId })\n }\n const taken = (): string[] => [...values.map((value) => value.id), ...spec.standardValues.map((value) => value.id)]\n for (const value of result.unmatched) {\n const choice = choices[value.key]\n if (choice?.action === 'mapTo') {\n const target = values.find((entry) => entry.id === choice.valueId)\n outcomes.set(value.key, target ? { kind: 'value', label: target.label, valueId: target.id } : { kind: 'blank' })\n } else if (choice?.action === 'addValue') {\n const label = normalizePicklistLabel(choice.label ?? value.value)\n const existing = values.find((entry) => picklistLabelKey(entry.label) === picklistLabelKey(label))\n if (existing) {\n outcomes.set(value.key, { kind: 'value', label: existing.label, valueId: existing.id })\n continue\n }\n const entry: PicklistValue = {\n id: mintPicklistValueId(label, taken()),\n label,\n active: true,\n ...(spec.groups?.length ? { group: choice.group ?? null } : {}),\n ...(spec.meanings?.length ? { meaning: choice.meaning ?? null } : {}),\n }\n values.push(entry)\n added.push(entry)\n outcomes.set(value.key, { kind: 'value', label: entry.label, valueId: entry.id })\n } else if (choice?.action === 'refuseRow') {\n outcomes.set(value.key, { kind: 'refuse' })\n } else {\n outcomes.set(value.key, { kind: 'blank' })\n }\n }\n return { set: { values, defaultValueId: set.defaultValueId }, added, outcomes }\n}\n\n/** One cell through a resolution: the label to store, blank, or refuse the row. */\nexport function resolvePicklistCell(resolution: PicklistResolution, raw: unknown): PicklistCellOutcome {\n const label = normalizePicklistLabel(raw)\n if (!label) return { kind: 'blank' }\n return resolution.outcomes.get(picklistLabelKey(label)) ?? { kind: 'blank' }\n}\n\n/**\n * A multi-value cell through a resolution: the labels to store, in order and\n * without repeats; `refuse` when any value refuses the row.\n */\nexport function resolveMultiPicklistCell(\n resolution: PicklistResolution,\n raw: readonly unknown[],\n): { kind: 'values'; labels: string[] } | { kind: 'refuse' } {\n const labels: string[] = []\n for (const entry of raw) {\n const outcome = resolvePicklistCell(resolution, entry)\n if (outcome.kind === 'refuse') return { kind: 'refuse' }\n if (outcome.kind === 'value' && !labels.includes(outcome.label)) labels.push(outcome.label)\n }\n return { kind: 'values', labels }\n}\n"],"names":["PICKLIST_VALUES_MAX","mintPicklistValueId","normalizePicklistLabel","picklistLabelKey","picklistValueByLabel","textSimilarity","PICKLIST_SAMPLE_ROWS","collectPicklistValues","cells","byKey","Map","row","value","values","Array","isArray","entry","label","key","seen","get","count","rows","length","includes","push","set","PICKLIST_SUGGESTION_THRESHOLD","matchPicklistValues","incoming","matched","unmatched","byLabel","byId","find","id","toLowerCase","valueId","inactive","active","suggestions","filter","map","confidence","Math","round","sort","a","b","slice","PICKLIST_AUTO_MAP_CONFIDENCE","proposePicklistChoice","spec","top","action","restricted","meanings","picklistChoiceProblems","choices","problems","labels","Set","added","choice","some","has","add","meaning","group","groups","resolvePicklistChoices","result","outcomes","kind","taken","standardValues","target","existing","defaultValueId","resolvePicklistCell","resolution","raw","resolveMultiPicklistCell","outcome"],"mappings":"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"}
|