@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,1007 @@
|
|
|
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
|
+
* DERIVATIONS — reading a cell as the field it was mapped to, and saying how.
|
|
19
|
+
*
|
|
20
|
+
* Every parser here returns the value AND a record of each thing it did to
|
|
21
|
+
* get there: a date read as day/month/year, a `1.234,56` read with a
|
|
22
|
+
* decimal comma, a `$` read as a currency, a full name split at its last
|
|
23
|
+
* word. Nothing is changed silently. The wizard counts the records by kind,
|
|
24
|
+
* shows samples, and a `flagged` record (a guess that could be wrong — an
|
|
25
|
+
* ambiguous date, a best-effort address) is a warning the person must
|
|
26
|
+
* acknowledge before anything is written.
|
|
27
|
+
*
|
|
28
|
+
* ## Three outcomes
|
|
29
|
+
*
|
|
30
|
+
* - blank — the cell was empty: `{ blank: true, value: null }`, never a problem.
|
|
31
|
+
* - read — `{ ok: true, value }`, with zero or more derivations.
|
|
32
|
+
* - unreadable — `{ ok: false, problem }`: the cell is dropped and reported,
|
|
33
|
+
* never stored as something it did not say.
|
|
34
|
+
*=========================================*/ import { normalizePhone } from "../foundation/definitions/contact.types.js";
|
|
35
|
+
function blankValue() {
|
|
36
|
+
return {
|
|
37
|
+
value: null,
|
|
38
|
+
blank: true,
|
|
39
|
+
ok: true,
|
|
40
|
+
derivations: []
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function readValue(value, derivations = []) {
|
|
44
|
+
return {
|
|
45
|
+
value,
|
|
46
|
+
blank: false,
|
|
47
|
+
ok: true,
|
|
48
|
+
derivations
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function unreadable(code, message) {
|
|
52
|
+
return {
|
|
53
|
+
value: null,
|
|
54
|
+
blank: false,
|
|
55
|
+
ok: false,
|
|
56
|
+
derivations: [],
|
|
57
|
+
problem: {
|
|
58
|
+
code,
|
|
59
|
+
message
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function derivation(kind, from, to, note, flagged = false) {
|
|
64
|
+
return {
|
|
65
|
+
kind,
|
|
66
|
+
from,
|
|
67
|
+
to: typeof to === 'string' ? to : JSON.stringify(to),
|
|
68
|
+
note,
|
|
69
|
+
flagged
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function cellText(raw) {
|
|
73
|
+
if (raw === null || raw === undefined) return '';
|
|
74
|
+
if (typeof raw === 'string') return raw.trim();
|
|
75
|
+
if (typeof raw === 'number' || typeof raw === 'boolean') return String(raw);
|
|
76
|
+
if (raw instanceof Date) return Number.isNaN(raw.getTime()) ? '' : raw.toISOString();
|
|
77
|
+
return String(raw).trim();
|
|
78
|
+
}
|
|
79
|
+
/*------------------------------------------
|
|
80
|
+
* Text
|
|
81
|
+
*-----------------------------------------*/ /** A text cell, trimmed; capped at `maxLength` with a flagged record when cut. */ export function deriveText(raw, options = {}) {
|
|
82
|
+
let text = options.multiline ? String(raw != null ? raw : '').replace(/\r\n?/g, '\n').trim() : cellText(raw);
|
|
83
|
+
if (!options.multiline) text = text.replace(/\s+/g, ' ');
|
|
84
|
+
if (!text) return blankValue();
|
|
85
|
+
if (options.maxLength && text.length > options.maxLength) {
|
|
86
|
+
const cut = text.slice(0, options.maxLength);
|
|
87
|
+
return readValue(cut, [
|
|
88
|
+
derivation('truncated', text, cut, `Cut to ${options.maxLength} characters`, true)
|
|
89
|
+
]);
|
|
90
|
+
}
|
|
91
|
+
return readValue(text);
|
|
92
|
+
}
|
|
93
|
+
/*------------------------------------------
|
|
94
|
+
* Boolean
|
|
95
|
+
*-----------------------------------------*/ const TRUE_WORDS = [
|
|
96
|
+
'yes',
|
|
97
|
+
'y',
|
|
98
|
+
'true',
|
|
99
|
+
'1',
|
|
100
|
+
'on',
|
|
101
|
+
'subscribed',
|
|
102
|
+
'opted in',
|
|
103
|
+
'opted-in'
|
|
104
|
+
];
|
|
105
|
+
const FALSE_WORDS = [
|
|
106
|
+
'no',
|
|
107
|
+
'n',
|
|
108
|
+
'false',
|
|
109
|
+
'0',
|
|
110
|
+
'off',
|
|
111
|
+
'unsubscribed',
|
|
112
|
+
''
|
|
113
|
+
];
|
|
114
|
+
/**
|
|
115
|
+
* A yes/no cell as a boolean, or `null` when it is neither.
|
|
116
|
+
*
|
|
117
|
+
* The affirmatives are the ones consent and checkbox columns actually
|
|
118
|
+
* carry; the negatives are listed so that an explicit `no` is a `false`
|
|
119
|
+
* rather than an unreadable value that gets reported as dropped. An empty
|
|
120
|
+
* cell reads as `false`, which is what a checkbox column means by it.
|
|
121
|
+
*/ export function parseImportFlag(value) {
|
|
122
|
+
if (typeof value === 'boolean') return value;
|
|
123
|
+
if (typeof value === 'number') return value === 1 ? true : value === 0 ? false : null;
|
|
124
|
+
const text = String(value != null ? value : '').trim().toLowerCase();
|
|
125
|
+
if (TRUE_WORDS.includes(text)) return true;
|
|
126
|
+
if (FALSE_WORDS.includes(text)) return false;
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
/** A boolean cell; a word other than true/false is recorded. */ export function deriveBoolean(raw) {
|
|
130
|
+
const text = cellText(raw);
|
|
131
|
+
if (!text) return blankValue();
|
|
132
|
+
const flag = parseImportFlag(typeof raw === 'string' ? text : raw);
|
|
133
|
+
if (flag === null) return unreadable('invalidBoolean', `"${text}" is not a yes or a no.`);
|
|
134
|
+
const plain = text.toLowerCase() === String(flag);
|
|
135
|
+
return readValue(flag, plain ? [] : [
|
|
136
|
+
derivation('booleanWord', text, String(flag), `Read "${text}" as ${flag ? 'yes' : 'no'}`)
|
|
137
|
+
]);
|
|
138
|
+
}
|
|
139
|
+
/*------------------------------------------
|
|
140
|
+
* Email, phone, URL
|
|
141
|
+
*-----------------------------------------*/ const EMAIL = /^[^\s@<>(),;:"[\]]+@[^\s@<>(),;:"[\]]+\.[^\s@<>(),;:"[\]]{2,}$/;
|
|
142
|
+
/** An address cell: `mailto:` and a display name stripped, lowercased, checked. */ export function deriveEmail(raw) {
|
|
143
|
+
const text = cellText(raw);
|
|
144
|
+
if (!text) return blankValue();
|
|
145
|
+
const derivations = [];
|
|
146
|
+
let address = text;
|
|
147
|
+
const angled = /<([^<>]+)>\s*$/.exec(address);
|
|
148
|
+
if (angled == null ? void 0 : angled[1]) {
|
|
149
|
+
address = angled[1].trim();
|
|
150
|
+
derivations.push(derivation('extracted', text, address, 'Took the address out of a name and address'));
|
|
151
|
+
}
|
|
152
|
+
if (/^mailto:/i.test(address)) {
|
|
153
|
+
var _address_replace_split_;
|
|
154
|
+
const stripped = (_address_replace_split_ = address.replace(/^mailto:/i, '').split('?')[0]) != null ? _address_replace_split_ : '';
|
|
155
|
+
derivations.push(derivation('extracted', address, stripped, 'Removed "mailto:"'));
|
|
156
|
+
address = stripped;
|
|
157
|
+
}
|
|
158
|
+
const lower = address.toLowerCase();
|
|
159
|
+
if (lower !== address) derivations.push(derivation('lowercased', address, lower, 'Lowercased the address'));
|
|
160
|
+
if (!EMAIL.test(lower)) return unreadable('invalidEmail', `"${text}" is not an email address.`);
|
|
161
|
+
return readValue(lower, derivations);
|
|
162
|
+
}
|
|
163
|
+
const EXTENSION = /\s*(?:ext\.?|extension|x|#)\s*(\d{1,6})\s*$/i;
|
|
164
|
+
/**
|
|
165
|
+
* A phone cell in E.164 through the platform's `normalizePhone`. A number it
|
|
166
|
+
* cannot normalize confidently is kept as typed and flagged — dropping a
|
|
167
|
+
* real number is worse than storing it unformatted. An extension is
|
|
168
|
+
* removed (E.164 has no place for it) and flagged.
|
|
169
|
+
*/ export function derivePhone(raw, options = {}) {
|
|
170
|
+
var _options_defaultCountry;
|
|
171
|
+
const text = cellText(raw);
|
|
172
|
+
if (!text) return blankValue();
|
|
173
|
+
const derivations = [];
|
|
174
|
+
let number = text;
|
|
175
|
+
const extension = EXTENSION.exec(number);
|
|
176
|
+
if (extension && number.replace(EXTENSION, '').replace(/\D/g, '').length >= 7) {
|
|
177
|
+
const without = number.replace(EXTENSION, '').trim();
|
|
178
|
+
derivations.push(derivation('phoneExtensionDropped', text, without, `Dropped extension ${extension[1]}`, true));
|
|
179
|
+
number = without;
|
|
180
|
+
}
|
|
181
|
+
const normalized = normalizePhone(number, (_options_defaultCountry = options.defaultCountry) != null ? _options_defaultCountry : 'US');
|
|
182
|
+
if (!normalized) {
|
|
183
|
+
derivations.push(derivation('phoneUnnormalized', text, number, 'Kept as typed: no country code to read it by', true));
|
|
184
|
+
return readValue(number, derivations);
|
|
185
|
+
}
|
|
186
|
+
if (normalized !== number) {
|
|
187
|
+
derivations.push(derivation('phoneNormalized', number, normalized, 'Written in international format'));
|
|
188
|
+
}
|
|
189
|
+
return readValue(normalized, derivations);
|
|
190
|
+
}
|
|
191
|
+
/** A web address cell: `https://` added to a bare domain, host lowercased, checked. */ export function deriveUrl(raw) {
|
|
192
|
+
const text = cellText(raw);
|
|
193
|
+
if (!text) return blankValue();
|
|
194
|
+
const derivations = [];
|
|
195
|
+
let candidate = text;
|
|
196
|
+
if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(candidate)) {
|
|
197
|
+
if (!/^(?:[\w-]+\.)+[a-z]{2,}(?::\d+)?(?:[/?#].*)?$/i.test(candidate)) {
|
|
198
|
+
return unreadable('invalidUrl', `"${text}" is not a web address.`);
|
|
199
|
+
}
|
|
200
|
+
candidate = `https://${candidate}`;
|
|
201
|
+
derivations.push(derivation('urlScheme', text, candidate, 'Added https://'));
|
|
202
|
+
}
|
|
203
|
+
let url;
|
|
204
|
+
try {
|
|
205
|
+
url = new URL(candidate);
|
|
206
|
+
} catch (unused) {
|
|
207
|
+
return unreadable('invalidUrl', `"${text}" is not a web address.`);
|
|
208
|
+
}
|
|
209
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
210
|
+
return unreadable('invalidUrl', `"${text}" is not a web address.`);
|
|
211
|
+
}
|
|
212
|
+
const rest = candidate.slice(candidate.indexOf('//') + 2).replace(/^[^/?#]*/, '');
|
|
213
|
+
return readValue(`${url.protocol}//${url.host}${rest}`, derivations);
|
|
214
|
+
}
|
|
215
|
+
const MONTHS = [
|
|
216
|
+
'jan',
|
|
217
|
+
'feb',
|
|
218
|
+
'mar',
|
|
219
|
+
'apr',
|
|
220
|
+
'may',
|
|
221
|
+
'jun',
|
|
222
|
+
'jul',
|
|
223
|
+
'aug',
|
|
224
|
+
'sep',
|
|
225
|
+
'oct',
|
|
226
|
+
'nov',
|
|
227
|
+
'dec'
|
|
228
|
+
];
|
|
229
|
+
function monthOf(word) {
|
|
230
|
+
var _full_at;
|
|
231
|
+
const key = word.toLowerCase().slice(0, 3);
|
|
232
|
+
const at = MONTHS.indexOf(key);
|
|
233
|
+
if (at < 0) return null;
|
|
234
|
+
// `sept` and full names are fine; a word that only starts like a month is not.
|
|
235
|
+
const full = [
|
|
236
|
+
'january',
|
|
237
|
+
'february',
|
|
238
|
+
'march',
|
|
239
|
+
'april',
|
|
240
|
+
'may',
|
|
241
|
+
'june',
|
|
242
|
+
'july',
|
|
243
|
+
'august',
|
|
244
|
+
'september',
|
|
245
|
+
'october',
|
|
246
|
+
'november',
|
|
247
|
+
'december'
|
|
248
|
+
];
|
|
249
|
+
const lower = word.toLowerCase();
|
|
250
|
+
return ((_full_at = full[at]) == null ? void 0 : _full_at.startsWith(lower)) ? at + 1 : null;
|
|
251
|
+
}
|
|
252
|
+
function pad(n, width = 2) {
|
|
253
|
+
return String(n).padStart(width, '0');
|
|
254
|
+
}
|
|
255
|
+
function isoDate(year, month, day) {
|
|
256
|
+
if (!Number.isInteger(year) || year < 1 || year > 9999) return null;
|
|
257
|
+
if (month < 1 || month > 12 || day < 1) return null;
|
|
258
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
259
|
+
date.setUTCFullYear(year);
|
|
260
|
+
if (date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day) return null;
|
|
261
|
+
return `${pad(year, 4)}-${pad(month)}-${pad(day)}`;
|
|
262
|
+
}
|
|
263
|
+
/** The spreadsheet epoch: serial day 0 is 1899-12-30 (the leap-year bug folded in). */ const SERIAL_EPOCH_MS = Date.UTC(1899, 11, 30);
|
|
264
|
+
const DAY_MS = 86400000;
|
|
265
|
+
function serialToDate(serial) {
|
|
266
|
+
return new Date(SERIAL_EPOCH_MS + Math.round(serial * DAY_MS));
|
|
267
|
+
}
|
|
268
|
+
function fullYear(text, pivot, from, derivations) {
|
|
269
|
+
const n = Number(text);
|
|
270
|
+
if (text.length !== 2) return n;
|
|
271
|
+
const year = n < pivot ? 2000 + n : 1900 + n;
|
|
272
|
+
derivations.push(derivation('twoDigitYear', from, String(year), `Read year "${text}" as ${year}`, true));
|
|
273
|
+
return year;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* A date cell as `YYYY-MM-DD`.
|
|
277
|
+
*
|
|
278
|
+
* ISO dates read as they are; `2024/03/05` and `20240305` are read year
|
|
279
|
+
* first; an all-number date with the year last is read by `order`, and
|
|
280
|
+
* under `auto` a value whose day and month could be swapped (`03/05/2024`)
|
|
281
|
+
* is read in `preferredOrder` and flagged; month names read in either
|
|
282
|
+
* order; a bare serial number is a spreadsheet's date.
|
|
283
|
+
*/ export function deriveDate(raw, options = {}) {
|
|
284
|
+
const derivations = [];
|
|
285
|
+
const result = parseDateText(raw, options, derivations);
|
|
286
|
+
if (result === undefined) return blankValue();
|
|
287
|
+
if (result === null) return unreadable('invalidDate', `"${cellText(raw)}" is not a date.`);
|
|
288
|
+
return readValue(result, derivations);
|
|
289
|
+
}
|
|
290
|
+
function parseDateText(raw, options, derivations) {
|
|
291
|
+
var _options_twoDigitYearPivot, _exec, _exec1, _exec2;
|
|
292
|
+
const text = cellText(raw);
|
|
293
|
+
if (!text) return undefined;
|
|
294
|
+
const pivot = (_options_twoDigitYearPivot = options.twoDigitYearPivot) != null ? _options_twoDigitYearPivot : 50;
|
|
295
|
+
const iso = /^(\d{4})-(\d{1,2})-(\d{1,2})(?:[T ](.+))?$/.exec(text);
|
|
296
|
+
if (iso) {
|
|
297
|
+
const date = isoDate(Number(iso[1]), Number(iso[2]), Number(iso[3]));
|
|
298
|
+
if (date && iso[4]) derivations.push(derivation('timeDropped', text, date, 'Kept the date, dropped the time'));
|
|
299
|
+
return date;
|
|
300
|
+
}
|
|
301
|
+
const yearFirst = (_exec = /^(\d{4})[/.](\d{1,2})[/.](\d{1,2})$/.exec(text)) != null ? _exec : /^(\d{4})(\d{2})(\d{2})$/.exec(text);
|
|
302
|
+
if (yearFirst) {
|
|
303
|
+
const date = isoDate(Number(yearFirst[1]), Number(yearFirst[2]), Number(yearFirst[3]));
|
|
304
|
+
if (date) derivations.push(derivation('dateFormat', text, date, 'Read as year/month/day'));
|
|
305
|
+
return date;
|
|
306
|
+
}
|
|
307
|
+
const numeric = /^(\d{1,2})[/.-](\d{1,2})[/.-](\d{2}|\d{4})$/.exec(text);
|
|
308
|
+
if (numeric) {
|
|
309
|
+
const a = Number(numeric[1]);
|
|
310
|
+
const b = Number(numeric[2]);
|
|
311
|
+
const yearDerivations = [];
|
|
312
|
+
const year = fullYear(numeric[3], pivot, text, yearDerivations);
|
|
313
|
+
let order;
|
|
314
|
+
let ambiguous = false;
|
|
315
|
+
if (options.order === 'mdy' || options.order === 'dmy') order = options.order;
|
|
316
|
+
else if (a > 12 && b <= 12) order = 'dmy';
|
|
317
|
+
else if (b > 12 && a <= 12) order = 'mdy';
|
|
318
|
+
else if (a > 12 && b > 12) return null;
|
|
319
|
+
else {
|
|
320
|
+
var _options_preferredOrder;
|
|
321
|
+
order = (_options_preferredOrder = options.preferredOrder) != null ? _options_preferredOrder : 'mdy';
|
|
322
|
+
ambiguous = a !== b;
|
|
323
|
+
}
|
|
324
|
+
const date = order === 'mdy' ? isoDate(year, a, b) : isoDate(year, b, a);
|
|
325
|
+
if (!date) return null;
|
|
326
|
+
const words = order === 'mdy' ? 'month/day/year' : 'day/month/year';
|
|
327
|
+
derivations.push(ambiguous ? derivation('ambiguousDate', text, date, `Could be either order; read as ${words}`, true) : derivation('dateFormat', text, date, `Read as ${words}`));
|
|
328
|
+
derivations.push(...yearDerivations);
|
|
329
|
+
return date;
|
|
330
|
+
}
|
|
331
|
+
const named = (_exec1 = /^(?:[a-z]+,?\s+)?(\d{1,2})(?:st|nd|rd|th)?[\s-]+([a-z]+)\.?,?[\s-]+(\d{2}|\d{4})$/i.exec(text)) != null ? _exec1 : null;
|
|
332
|
+
const namedMonthFirst = (_exec2 = /^(?:[a-z]+,\s+)?([a-z]+)\.?[\s-]+(\d{1,2})(?:st|nd|rd|th)?,?[\s-]+(\d{2}|\d{4})$/i.exec(text)) != null ? _exec2 : null;
|
|
333
|
+
if (named || namedMonthFirst) {
|
|
334
|
+
const day = Number(named ? named[1] : namedMonthFirst == null ? void 0 : namedMonthFirst[2]);
|
|
335
|
+
const month = monthOf(named ? named[2] : namedMonthFirst == null ? void 0 : namedMonthFirst[1]);
|
|
336
|
+
if (!month) return null;
|
|
337
|
+
const yearDerivations = [];
|
|
338
|
+
const year = fullYear(named ? named[3] : namedMonthFirst == null ? void 0 : namedMonthFirst[3], pivot, text, yearDerivations);
|
|
339
|
+
const date = isoDate(year, month, day);
|
|
340
|
+
if (!date) return null;
|
|
341
|
+
derivations.push(derivation('dateFormat', text, date, 'Read the month by name'), ...yearDerivations);
|
|
342
|
+
return date;
|
|
343
|
+
}
|
|
344
|
+
const serial = typeof raw === 'number' ? raw : /^\d{5}(?:\.\d+)?$/.test(text) ? Number(text) : NaN;
|
|
345
|
+
if (options.excelSerials !== false && Number.isFinite(serial) && serial >= 1 && serial <= 2958465) {
|
|
346
|
+
const at = serialToDate(serial);
|
|
347
|
+
const date = isoDate(at.getUTCFullYear(), at.getUTCMonth() + 1, at.getUTCDate());
|
|
348
|
+
if (date) derivations.push(derivation('excelSerial', text, date, 'Read as a spreadsheet serial date', true));
|
|
349
|
+
return date;
|
|
350
|
+
}
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
const ZONED_ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})$/i;
|
|
354
|
+
function zoneLabel(offsetMinutes) {
|
|
355
|
+
if (!offsetMinutes) return 'UTC';
|
|
356
|
+
const sign = offsetMinutes > 0 ? '+' : '-';
|
|
357
|
+
const abs = Math.abs(offsetMinutes);
|
|
358
|
+
return `UTC${sign}${pad(Math.floor(abs / 60))}:${pad(abs % 60)}`;
|
|
359
|
+
}
|
|
360
|
+
function offsetOf(zone) {
|
|
361
|
+
if (/^(?:z|utc|gmt)$/i.test(zone)) return 0;
|
|
362
|
+
const match = /^([+-])(\d{2}):?(\d{2})$/.exec(zone);
|
|
363
|
+
if (!match) return null;
|
|
364
|
+
const minutes = Number(match[2]) * 60 + Number(match[3]);
|
|
365
|
+
return match[1] === '-' ? -minutes : minutes;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* A date-and-time cell as an ISO instant (`…Z`).
|
|
369
|
+
*
|
|
370
|
+
* A time with a zone is exact. A time without one is read in
|
|
371
|
+
* `offsetMinutes` and flagged; a date alone is midnight there. A ten- or
|
|
372
|
+
* thirteen-digit number is a Unix time in seconds or milliseconds, and a
|
|
373
|
+
* serial number with a fraction is a spreadsheet's date and time — both
|
|
374
|
+
* flagged, because a column of numbers could be something else.
|
|
375
|
+
*/ export function deriveDateTime(raw, options = {}) {
|
|
376
|
+
var _options_offsetMinutes;
|
|
377
|
+
const text = cellText(raw);
|
|
378
|
+
if (!text) return blankValue();
|
|
379
|
+
const fail = ()=>unreadable('invalidDateTime', `"${text}" is not a date and time.`);
|
|
380
|
+
const offset = (_options_offsetMinutes = options.offsetMinutes) != null ? _options_offsetMinutes : 0;
|
|
381
|
+
if (ZONED_ISO.test(text)) {
|
|
382
|
+
const ms = Date.parse(text);
|
|
383
|
+
return Number.isNaN(ms) ? fail() : readValue(new Date(ms).toISOString());
|
|
384
|
+
}
|
|
385
|
+
if (/^\d{10}$|^\d{13}$/.test(text)) {
|
|
386
|
+
const ms = text.length === 10 ? Number(text) * 1000 : Number(text);
|
|
387
|
+
const iso = new Date(ms).toISOString();
|
|
388
|
+
return readValue(iso, [
|
|
389
|
+
derivation('epochTime', text, iso, `Read as a Unix time in ${text.length === 10 ? 'seconds' : 'milliseconds'}`, true)
|
|
390
|
+
]);
|
|
391
|
+
}
|
|
392
|
+
const serial = typeof raw === 'number' ? raw : /^\d{5}\.\d+$/.test(text) ? Number(text) : NaN;
|
|
393
|
+
if (options.excelSerials !== false && Number.isFinite(serial) && serial >= 1 && serial <= 2958465) {
|
|
394
|
+
const iso = new Date(serialToDate(serial).getTime() - offset * 60000).toISOString();
|
|
395
|
+
return readValue(iso, [
|
|
396
|
+
derivation('excelSerial', text, iso, 'Read as a spreadsheet serial date and time', true)
|
|
397
|
+
]);
|
|
398
|
+
}
|
|
399
|
+
const timed = /^(.*?)[T\s,]+(\d{1,2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?\s*([ap]\.?m\.?)?\s*(z|utc|gmt|[+-]\d{2}:?\d{2})?$/i.exec(text);
|
|
400
|
+
const derivations = [];
|
|
401
|
+
const datePart = timed ? timed[1] : text;
|
|
402
|
+
const date = parseDateText(datePart, options, derivations);
|
|
403
|
+
if (!date) return fail();
|
|
404
|
+
let hours = 0;
|
|
405
|
+
let minutes = 0;
|
|
406
|
+
let seconds = 0;
|
|
407
|
+
let zoneOffset = null;
|
|
408
|
+
if (timed) {
|
|
409
|
+
var _timed_;
|
|
410
|
+
var _timed_1;
|
|
411
|
+
hours = Number(timed[2]);
|
|
412
|
+
minutes = Number(timed[3]);
|
|
413
|
+
seconds = Number((_timed_ = timed[4]) != null ? _timed_ : 0);
|
|
414
|
+
const meridiem = (_timed_1 = timed[5]) == null ? void 0 : _timed_1.toLowerCase().replace(/\./g, '');
|
|
415
|
+
if (meridiem) {
|
|
416
|
+
if (hours < 1 || hours > 12) return fail();
|
|
417
|
+
if (meridiem === 'pm' && hours !== 12) hours += 12;
|
|
418
|
+
if (meridiem === 'am' && hours === 12) hours = 0;
|
|
419
|
+
}
|
|
420
|
+
if (hours > 23 || minutes > 59 || seconds > 59) return fail();
|
|
421
|
+
if (timed[6]) {
|
|
422
|
+
zoneOffset = offsetOf(timed[6]);
|
|
423
|
+
if (zoneOffset === null) return fail();
|
|
424
|
+
}
|
|
425
|
+
} else {
|
|
426
|
+
derivations.push(derivation('timeAssumed', text, '00:00', 'No time given; read as midnight'));
|
|
427
|
+
}
|
|
428
|
+
// A date-only cell is a day, not a moment someone was unsure of the zone
|
|
429
|
+
// of — only a cell that HAS a time without a zone is flagged.
|
|
430
|
+
if (zoneOffset === null && timed) {
|
|
431
|
+
derivations.push(derivation('zoneAssumed', text, zoneLabel(offset), `No time zone; read as ${zoneLabel(offset)}`, true));
|
|
432
|
+
}
|
|
433
|
+
const [y, m, d] = date.split('-').map(Number);
|
|
434
|
+
const local = new Date(Date.UTC(2000, m - 1, d, hours, minutes, seconds));
|
|
435
|
+
// `Date.UTC` reads a year below 100 as 19xx; the year is set on its own.
|
|
436
|
+
local.setUTCFullYear(y, m - 1, d);
|
|
437
|
+
const at = new Date(local.getTime() - (zoneOffset != null ? zoneOffset : offset) * 60000);
|
|
438
|
+
return readValue(at.toISOString(), derivations);
|
|
439
|
+
}
|
|
440
|
+
const GROUPED_COMMA = /^\d{1,3}(?:,\d{3})+$/;
|
|
441
|
+
const GROUPED_DOT = /^\d{1,3}(?:\.\d{3})+$/;
|
|
442
|
+
const PLAIN_NUMBER = /^\d+(?:\.\d+)?(?:e[+-]?\d+)?$|^\.\d+$/i;
|
|
443
|
+
/**
|
|
444
|
+
* A locale-formatted number: separators read, parentheses as a minus.
|
|
445
|
+
* `null` when the text is not a number. Every separator decision is
|
|
446
|
+
* recorded; a lone `1,234` or `1.234` under `auto` could be a thousand or
|
|
447
|
+
* one-and-a-bit, so it is read as the thousand and flagged.
|
|
448
|
+
*/ export function parseLocaleNumber(text, options = {}, derivations = []) {
|
|
449
|
+
var _options_decimal;
|
|
450
|
+
const from = text;
|
|
451
|
+
// Spaces (plain, non-breaking, narrow) and apostrophes only ever group thousands.
|
|
452
|
+
let body = text.trim().replace(/[\s\u00a0\u202f'\u2019]+/g, '_');
|
|
453
|
+
let negative = false;
|
|
454
|
+
const paren = /^\((.*)\)$/.exec(body);
|
|
455
|
+
if (paren) {
|
|
456
|
+
body = paren[1];
|
|
457
|
+
negative = true;
|
|
458
|
+
derivations.push(derivation('negativeParentheses', from, `-${body}`, 'Read parentheses as a minus'));
|
|
459
|
+
}
|
|
460
|
+
if (/^[+-]/.test(body)) {
|
|
461
|
+
if (body.startsWith('-')) negative = !negative;
|
|
462
|
+
body = body.slice(1);
|
|
463
|
+
} else if (/-$/.test(body)) {
|
|
464
|
+
negative = !negative;
|
|
465
|
+
body = body.slice(0, -1);
|
|
466
|
+
}
|
|
467
|
+
if (body.includes('_')) {
|
|
468
|
+
if (!/^\d{1,3}(?:_\d{3})+(?:[.,]\d+)?$/.test(body)) return null;
|
|
469
|
+
body = body.replace(/_/g, '');
|
|
470
|
+
derivations.push(derivation('thousandsSeparator', from, body, 'Removed the thousands separators'));
|
|
471
|
+
}
|
|
472
|
+
const decimal = (_options_decimal = options.decimal) != null ? _options_decimal : 'auto';
|
|
473
|
+
const hasDot = body.includes('.');
|
|
474
|
+
const hasComma = body.includes(',');
|
|
475
|
+
if (hasDot && hasComma) {
|
|
476
|
+
const commaLast = body.lastIndexOf(',') > body.lastIndexOf('.');
|
|
477
|
+
const point = decimal === 'auto' ? commaLast ? ',' : '.' : decimal;
|
|
478
|
+
const group = point === ',' ? '.' : ',';
|
|
479
|
+
const [whole, fraction, extra] = body.split(point);
|
|
480
|
+
if (extra !== undefined || !whole || !fraction) return null;
|
|
481
|
+
if (!(group === '.' ? GROUPED_DOT : GROUPED_COMMA).test(whole)) return null;
|
|
482
|
+
body = `${whole.split(group).join('')}.${fraction}`;
|
|
483
|
+
derivations.push(derivation('thousandsSeparator', from, body, `Read "${group}" as the thousands separator`));
|
|
484
|
+
if (point === ',') derivations.push(derivation('decimalComma', from, body, 'Read "," as the decimal point'));
|
|
485
|
+
} else if (hasComma) {
|
|
486
|
+
if (decimal === ',' || decimal === 'auto' && !GROUPED_COMMA.test(body)) {
|
|
487
|
+
var _body_match;
|
|
488
|
+
if (((_body_match = body.match(/,/g)) != null ? _body_match : []).length > 1) return null;
|
|
489
|
+
body = body.replace(',', '.');
|
|
490
|
+
derivations.push(derivation('decimalComma', from, body, 'Read "," as the decimal point'));
|
|
491
|
+
} else {
|
|
492
|
+
var _body_match1;
|
|
493
|
+
if (!GROUPED_COMMA.test(body)) return null;
|
|
494
|
+
const ambiguous = decimal === 'auto' && ((_body_match1 = body.match(/,/g)) != null ? _body_match1 : []).length === 1;
|
|
495
|
+
body = body.replace(/,/g, '');
|
|
496
|
+
derivations.push(ambiguous ? derivation('ambiguousNumber', from, body, 'Read "," as the thousands separator; it could be a decimal comma', true) : derivation('thousandsSeparator', from, body, 'Read "," as the thousands separator'));
|
|
497
|
+
}
|
|
498
|
+
} else if (hasDot) {
|
|
499
|
+
var _body_match2;
|
|
500
|
+
const dots = ((_body_match2 = body.match(/\./g)) != null ? _body_match2 : []).length;
|
|
501
|
+
if (dots > 1 || decimal === ',' && GROUPED_DOT.test(body)) {
|
|
502
|
+
if (!GROUPED_DOT.test(body)) return null;
|
|
503
|
+
body = body.replace(/\./g, '');
|
|
504
|
+
derivations.push(derivation('thousandsSeparator', from, body, 'Read "." as the thousands separator'));
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (!PLAIN_NUMBER.test(body)) return null;
|
|
508
|
+
const value = Number(body);
|
|
509
|
+
if (!Number.isFinite(value)) return null;
|
|
510
|
+
return negative ? -value : value;
|
|
511
|
+
}
|
|
512
|
+
/** A number cell. */ export function deriveNumber(raw, options = {}) {
|
|
513
|
+
if (typeof raw === 'number') return Number.isFinite(raw) ? readValue(raw) : unreadable('invalidNumber', 'Not a number.');
|
|
514
|
+
const text = cellText(raw);
|
|
515
|
+
if (!text) return blankValue();
|
|
516
|
+
const derivations = [];
|
|
517
|
+
const value = parseLocaleNumber(text, options, derivations);
|
|
518
|
+
if (value === null) return unreadable('invalidNumber', `"${text}" is not a number.`);
|
|
519
|
+
return readValue(value, derivations);
|
|
520
|
+
}
|
|
521
|
+
/** A whole-number cell; a fraction is unreadable rather than rounded away. */ export function deriveInteger(raw, options = {}) {
|
|
522
|
+
const result = deriveNumber(raw, options);
|
|
523
|
+
if (!result.ok || result.value === null) return result;
|
|
524
|
+
if (!Number.isInteger(result.value)) {
|
|
525
|
+
return unreadable('notInteger', `"${cellText(raw)}" is not a whole number.`);
|
|
526
|
+
}
|
|
527
|
+
return result;
|
|
528
|
+
}
|
|
529
|
+
/** Currencies whose smallest unit is not the hundredth. */ export const CURRENCY_MINOR_UNITS = {
|
|
530
|
+
BHD: 3,
|
|
531
|
+
CLP: 0,
|
|
532
|
+
ISK: 0,
|
|
533
|
+
JOD: 3,
|
|
534
|
+
JPY: 0,
|
|
535
|
+
KRW: 0,
|
|
536
|
+
KWD: 3,
|
|
537
|
+
OMR: 3,
|
|
538
|
+
TND: 3,
|
|
539
|
+
UGX: 0,
|
|
540
|
+
VND: 0,
|
|
541
|
+
XAF: 0,
|
|
542
|
+
XOF: 0
|
|
543
|
+
};
|
|
544
|
+
/** How many decimal places a currency's smallest unit is. */ export function currencyMinorUnits(currency) {
|
|
545
|
+
var _CURRENCY_MINOR_UNITS_currency_toUpperCase;
|
|
546
|
+
return (_CURRENCY_MINOR_UNITS_currency_toUpperCase = CURRENCY_MINOR_UNITS[currency.toUpperCase()]) != null ? _CURRENCY_MINOR_UNITS_currency_toUpperCase : 2;
|
|
547
|
+
}
|
|
548
|
+
/** Symbols longest first, so `US$` is found before `$`. */ const CURRENCY_SYMBOLS = [
|
|
549
|
+
[
|
|
550
|
+
'US$',
|
|
551
|
+
'USD'
|
|
552
|
+
],
|
|
553
|
+
[
|
|
554
|
+
'CA$',
|
|
555
|
+
'CAD'
|
|
556
|
+
],
|
|
557
|
+
[
|
|
558
|
+
'AU$',
|
|
559
|
+
'AUD'
|
|
560
|
+
],
|
|
561
|
+
[
|
|
562
|
+
'NZ$',
|
|
563
|
+
'NZD'
|
|
564
|
+
],
|
|
565
|
+
[
|
|
566
|
+
'HK$',
|
|
567
|
+
'HKD'
|
|
568
|
+
],
|
|
569
|
+
[
|
|
570
|
+
'R$',
|
|
571
|
+
'BRL'
|
|
572
|
+
],
|
|
573
|
+
[
|
|
574
|
+
'A$',
|
|
575
|
+
'AUD'
|
|
576
|
+
],
|
|
577
|
+
[
|
|
578
|
+
'C$',
|
|
579
|
+
'CAD'
|
|
580
|
+
],
|
|
581
|
+
[
|
|
582
|
+
'€',
|
|
583
|
+
'EUR'
|
|
584
|
+
],
|
|
585
|
+
[
|
|
586
|
+
'£',
|
|
587
|
+
'GBP'
|
|
588
|
+
],
|
|
589
|
+
[
|
|
590
|
+
'¥',
|
|
591
|
+
'JPY'
|
|
592
|
+
],
|
|
593
|
+
[
|
|
594
|
+
'₹',
|
|
595
|
+
'INR'
|
|
596
|
+
],
|
|
597
|
+
[
|
|
598
|
+
'₩',
|
|
599
|
+
'KRW'
|
|
600
|
+
],
|
|
601
|
+
[
|
|
602
|
+
'₪',
|
|
603
|
+
'ILS'
|
|
604
|
+
],
|
|
605
|
+
[
|
|
606
|
+
'₱',
|
|
607
|
+
'PHP'
|
|
608
|
+
],
|
|
609
|
+
[
|
|
610
|
+
'₫',
|
|
611
|
+
'VND'
|
|
612
|
+
],
|
|
613
|
+
[
|
|
614
|
+
'₺',
|
|
615
|
+
'TRY'
|
|
616
|
+
],
|
|
617
|
+
[
|
|
618
|
+
'$',
|
|
619
|
+
null
|
|
620
|
+
]
|
|
621
|
+
];
|
|
622
|
+
const DOLLAR_CURRENCIES = [
|
|
623
|
+
'USD',
|
|
624
|
+
'CAD',
|
|
625
|
+
'AUD',
|
|
626
|
+
'NZD',
|
|
627
|
+
'HKD',
|
|
628
|
+
'SGD',
|
|
629
|
+
'MXN'
|
|
630
|
+
];
|
|
631
|
+
/**
|
|
632
|
+
* A money cell as an amount in minor units and a currency. A symbol or a
|
|
633
|
+
* three-letter code on either side names the currency; `$` alone is the
|
|
634
|
+
* default currency when that is a dollar, else US dollars; a bare number
|
|
635
|
+
* is the default currency. More decimals than the currency has are rounded
|
|
636
|
+
* and flagged.
|
|
637
|
+
*/ export function deriveCurrency(raw, options = {}) {
|
|
638
|
+
var _options_defaultCurrency, _exec;
|
|
639
|
+
const fallback = ((_options_defaultCurrency = options.defaultCurrency) != null ? _options_defaultCurrency : 'USD').toUpperCase();
|
|
640
|
+
const text = cellText(raw);
|
|
641
|
+
if (!text) return blankValue();
|
|
642
|
+
const derivations = [];
|
|
643
|
+
let body = text;
|
|
644
|
+
let currency = null;
|
|
645
|
+
const coded = (_exec = /^([a-z]{3})\s*(.+)$/i.exec(body)) != null ? _exec : /^(.+?)\s*([a-z]{3})$/i.exec(body);
|
|
646
|
+
if (coded) {
|
|
647
|
+
const codeFirst = /^[a-z]{3}$/i.test(coded[1]) && !/^\d/.test(coded[1]);
|
|
648
|
+
const code = codeFirst ? coded[1] : coded[2];
|
|
649
|
+
if (/^[a-z]{3}$/i.test(code) && !/^e[+-]?\d/i.test(code)) {
|
|
650
|
+
currency = code.toUpperCase();
|
|
651
|
+
body = (codeFirst ? coded[2] : coded[1]).trim();
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
for (const [symbol, code] of CURRENCY_SYMBOLS){
|
|
655
|
+
const at = body.indexOf(symbol);
|
|
656
|
+
if (at < 0) continue;
|
|
657
|
+
body = (body.slice(0, at) + body.slice(at + symbol.length)).trim();
|
|
658
|
+
const named = code != null ? code : DOLLAR_CURRENCIES.includes(fallback) ? fallback : 'USD';
|
|
659
|
+
if (!currency) currency = named;
|
|
660
|
+
derivations.push(derivation('currencySymbol', text, currency, `Read "${symbol}" as ${currency}`));
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
if (!currency) {
|
|
664
|
+
currency = fallback;
|
|
665
|
+
derivations.push(derivation('currencyAssumed', text, currency, `No currency given; read as ${currency}`));
|
|
666
|
+
}
|
|
667
|
+
const value = parseLocaleNumber(body, options, derivations);
|
|
668
|
+
if (value === null) return unreadable('invalidCurrency', `"${text}" is not an amount of money.`);
|
|
669
|
+
const units = currencyMinorUnits(currency);
|
|
670
|
+
const scaled = value * 10 ** units;
|
|
671
|
+
const amountMinor = Math.round(scaled);
|
|
672
|
+
if (Math.abs(scaled - amountMinor) > 1e-6) {
|
|
673
|
+
derivations.push(derivation('rounded', text, String(amountMinor / 10 ** units), `Rounded to ${units} decimal places`, true));
|
|
674
|
+
}
|
|
675
|
+
return readValue({
|
|
676
|
+
amountMinor,
|
|
677
|
+
currency
|
|
678
|
+
}, derivations);
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* A percent cell. `12%` is twelve percent. A number with no `%` between 0
|
|
682
|
+
* and 1 (`0.12`) is read as a fraction — twelve percent — and flagged,
|
|
683
|
+
* because a file of fractions and a file of tiny percents look the same.
|
|
684
|
+
*/ export function derivePercent(raw, options = {}) {
|
|
685
|
+
const text = cellText(raw);
|
|
686
|
+
if (!text) return blankValue();
|
|
687
|
+
const derivations = [];
|
|
688
|
+
const signed = /%\s*$|^\s*%/.test(text);
|
|
689
|
+
const value = parseLocaleNumber(text.replace(/%/g, '').trim(), options, derivations);
|
|
690
|
+
if (value === null) return unreadable('invalidPercent', `"${text}" is not a percent.`);
|
|
691
|
+
let whole = value;
|
|
692
|
+
if (!signed && value !== 0 && Math.abs(value) < 1) {
|
|
693
|
+
whole = Number((value * 100).toPrecision(12));
|
|
694
|
+
derivations.push(derivation('percentScaled', text, `${whole}%`, `Read ${text} as a fraction: ${whole}%`, true));
|
|
695
|
+
}
|
|
696
|
+
return readValue(options.scale === 'fraction' ? Number((whole / 100).toPrecision(12)) : whole, derivations);
|
|
697
|
+
}
|
|
698
|
+
const HONORIFICS = [
|
|
699
|
+
'mr',
|
|
700
|
+
'mrs',
|
|
701
|
+
'ms',
|
|
702
|
+
'miss',
|
|
703
|
+
'mx',
|
|
704
|
+
'dr',
|
|
705
|
+
'prof',
|
|
706
|
+
'sir',
|
|
707
|
+
'dame',
|
|
708
|
+
'rev'
|
|
709
|
+
];
|
|
710
|
+
const SUFFIXES = [
|
|
711
|
+
'jr',
|
|
712
|
+
'sr',
|
|
713
|
+
'ii',
|
|
714
|
+
'iii',
|
|
715
|
+
'iv',
|
|
716
|
+
'v',
|
|
717
|
+
'phd',
|
|
718
|
+
'md',
|
|
719
|
+
'esq',
|
|
720
|
+
'dds',
|
|
721
|
+
'cpa'
|
|
722
|
+
];
|
|
723
|
+
const PARTICLES = [
|
|
724
|
+
'van',
|
|
725
|
+
'von',
|
|
726
|
+
'de',
|
|
727
|
+
'der',
|
|
728
|
+
'den',
|
|
729
|
+
'da',
|
|
730
|
+
'das',
|
|
731
|
+
'dos',
|
|
732
|
+
'del',
|
|
733
|
+
'della',
|
|
734
|
+
'di',
|
|
735
|
+
'du',
|
|
736
|
+
'la',
|
|
737
|
+
'le',
|
|
738
|
+
'bin',
|
|
739
|
+
'binti',
|
|
740
|
+
'al',
|
|
741
|
+
'el',
|
|
742
|
+
'ter',
|
|
743
|
+
'ten',
|
|
744
|
+
'st',
|
|
745
|
+
'st.'
|
|
746
|
+
];
|
|
747
|
+
function bare(word) {
|
|
748
|
+
return word.toLowerCase().replace(/[.,]/g, '');
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* A full name as first and last. "Last, First" splits at the comma; an
|
|
752
|
+
* honorific is dropped (and recorded); a suffix stays with the last name; a
|
|
753
|
+
* surname particle (`van`, `de la`) starts the last name; otherwise the
|
|
754
|
+
* last word is the last name. Every split is recorded with its rule.
|
|
755
|
+
*/ export function splitFullName(raw) {
|
|
756
|
+
const text = cellText(raw).replace(/\s+/g, ' ');
|
|
757
|
+
if (!text) return blankValue();
|
|
758
|
+
const derivations = [];
|
|
759
|
+
const done = (first, last, rule, note)=>{
|
|
760
|
+
derivations.push(derivation('nameSplit', text, {
|
|
761
|
+
first,
|
|
762
|
+
last
|
|
763
|
+
}, note));
|
|
764
|
+
return readValue({
|
|
765
|
+
first: first || null,
|
|
766
|
+
last: last || null,
|
|
767
|
+
rule
|
|
768
|
+
}, derivations);
|
|
769
|
+
};
|
|
770
|
+
const comma = /^([^,]+),\s*([^,]+)$/.exec(text);
|
|
771
|
+
if (comma && !SUFFIXES.includes(bare(comma[2]))) {
|
|
772
|
+
return done(comma[2].trim(), comma[1].trim(), 'lastCommaFirst', 'Read as "Last, First"');
|
|
773
|
+
}
|
|
774
|
+
let words = text.replace(/,/g, ' ').split(' ').filter(Boolean);
|
|
775
|
+
while(words.length > 1 && HONORIFICS.includes(bare(words[0]))){
|
|
776
|
+
derivations.push(derivation('honorificDropped', text, words[0], `Dropped "${words[0]}"`));
|
|
777
|
+
words = words.slice(1);
|
|
778
|
+
}
|
|
779
|
+
const suffixes = [];
|
|
780
|
+
while(words.length > 2 && SUFFIXES.includes(bare(words[words.length - 1]))){
|
|
781
|
+
suffixes.unshift(words.pop());
|
|
782
|
+
}
|
|
783
|
+
if (words.length === 1) return done(words[0], null, 'singleWord', 'One word; kept as the first name');
|
|
784
|
+
const particleAt = words.findIndex((word, index)=>index > 0 && index < words.length - 1 && PARTICLES.includes(word.toLowerCase()));
|
|
785
|
+
const tail = suffixes.length ? ` ${suffixes.join(' ')}` : '';
|
|
786
|
+
if (particleAt > 0) {
|
|
787
|
+
return done(words.slice(0, particleAt).join(' '), words.slice(particleAt).join(' ') + tail, 'surnameParticle', `Last name starts at "${words[particleAt]}"`);
|
|
788
|
+
}
|
|
789
|
+
return done(words.slice(0, -1).join(' '), words[words.length - 1] + tail, 'lastWord', 'Last word is the last name');
|
|
790
|
+
}
|
|
791
|
+
const COUNTRY_NAMES = {
|
|
792
|
+
'us': 'US',
|
|
793
|
+
'usa': 'US',
|
|
794
|
+
'u s a': 'US',
|
|
795
|
+
'united states': 'US',
|
|
796
|
+
'united states of america': 'US',
|
|
797
|
+
'america': 'US',
|
|
798
|
+
'ca': 'CA',
|
|
799
|
+
'canada': 'CA',
|
|
800
|
+
'uk': 'GB',
|
|
801
|
+
'gb': 'GB',
|
|
802
|
+
'united kingdom': 'GB',
|
|
803
|
+
'great britain': 'GB',
|
|
804
|
+
'england': 'GB',
|
|
805
|
+
'scotland': 'GB',
|
|
806
|
+
'wales': 'GB',
|
|
807
|
+
'ireland': 'IE',
|
|
808
|
+
'australia': 'AU',
|
|
809
|
+
'new zealand': 'NZ',
|
|
810
|
+
'germany': 'DE',
|
|
811
|
+
'deutschland': 'DE',
|
|
812
|
+
'france': 'FR',
|
|
813
|
+
'spain': 'ES',
|
|
814
|
+
'italy': 'IT',
|
|
815
|
+
'netherlands': 'NL',
|
|
816
|
+
'mexico': 'MX',
|
|
817
|
+
'india': 'IN',
|
|
818
|
+
'japan': 'JP',
|
|
819
|
+
'brazil': 'BR'
|
|
820
|
+
};
|
|
821
|
+
function countryOf(part) {
|
|
822
|
+
var _COUNTRY_NAMES_key;
|
|
823
|
+
const key = part.toLowerCase().replace(/[.]/g, '').replace(/\s+/g, ' ').trim();
|
|
824
|
+
return (_COUNTRY_NAMES_key = COUNTRY_NAMES[key]) != null ? _COUNTRY_NAMES_key : null;
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* A one-line address as parts, best effort, always flagged: commas split
|
|
828
|
+
* it; a trailing country name becomes its two-letter code; `TX 78701`,
|
|
829
|
+
* a bare postal code or a two-letter region is read from the end; the part
|
|
830
|
+
* before that is the city; the rest is the street.
|
|
831
|
+
*/ export function parseAddressLine(raw) {
|
|
832
|
+
if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
|
|
833
|
+
return readValue(raw);
|
|
834
|
+
}
|
|
835
|
+
const text = cellText(raw).replace(/\s*\n\s*/g, ', ');
|
|
836
|
+
if (!text) return blankValue();
|
|
837
|
+
const parts = text.split(',').map((part)=>part.trim()).filter(Boolean);
|
|
838
|
+
const address = {};
|
|
839
|
+
const last = parts[parts.length - 1];
|
|
840
|
+
if (parts.length > 1 && last) {
|
|
841
|
+
const country = countryOf(last);
|
|
842
|
+
if (country) {
|
|
843
|
+
address.country = country;
|
|
844
|
+
parts.pop();
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
const tail = parts[parts.length - 1];
|
|
848
|
+
if (parts.length > 1 && tail) {
|
|
849
|
+
const regionPostal = /^([A-Za-z][A-Za-z .]{1,30}?)\s+([A-Z0-9]{3,10}(?:[ -][A-Z0-9]{2,5})?)$/i.exec(tail);
|
|
850
|
+
if (regionPostal && /\d/.test(regionPostal[2])) {
|
|
851
|
+
address.state = regionPostal[1].trim();
|
|
852
|
+
address.postalCode = regionPostal[2].toUpperCase();
|
|
853
|
+
parts.pop();
|
|
854
|
+
} else if (/^[A-Z0-9]{3,10}(?:[ -][A-Z0-9]{2,5})?$/i.test(tail) && /\d/.test(tail)) {
|
|
855
|
+
address.postalCode = tail.toUpperCase();
|
|
856
|
+
parts.pop();
|
|
857
|
+
} else if (/^[A-Za-z]{2}$/.test(tail) && parts.length > 2) {
|
|
858
|
+
address.state = tail.toUpperCase();
|
|
859
|
+
parts.pop();
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
if (parts.length > 1) address.city = parts.pop();
|
|
863
|
+
if (parts.length) address.line1 = parts.join(', ');
|
|
864
|
+
return readValue(address, [
|
|
865
|
+
derivation('addressSplit', text, address, 'Split one line into street, city, region, postal code and country', true)
|
|
866
|
+
]);
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* A list cell as its items: split on `,` `;` `|` or line breaks, trimmed,
|
|
870
|
+
* duplicates (in any case) dropped keeping the first spelling. An array
|
|
871
|
+
* (from a JSON file) is taken item by item.
|
|
872
|
+
*/ export function splitTransferList(raw, options = {}) {
|
|
873
|
+
var _options_separators;
|
|
874
|
+
const parts = Array.isArray(raw) ? raw.map((item)=>cellText(item)) : cellText(raw).split((_options_separators = options.separators) != null ? _options_separators : /[,;|\n]/);
|
|
875
|
+
const text = Array.isArray(raw) ? JSON.stringify(raw) : cellText(raw);
|
|
876
|
+
const items = [];
|
|
877
|
+
const seen = new Set();
|
|
878
|
+
let duplicates = 0;
|
|
879
|
+
for (const part of parts){
|
|
880
|
+
const item = options.lowercase ? part.trim().toLowerCase() : part.trim();
|
|
881
|
+
if (!item) continue;
|
|
882
|
+
const key = item.toLowerCase();
|
|
883
|
+
if (seen.has(key)) {
|
|
884
|
+
duplicates += 1;
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
seen.add(key);
|
|
888
|
+
items.push(item);
|
|
889
|
+
}
|
|
890
|
+
if (!items.length) return blankValue();
|
|
891
|
+
const derivations = [];
|
|
892
|
+
if (!Array.isArray(raw) && items.length + duplicates > 1) {
|
|
893
|
+
derivations.push(derivation('listSplit', text, items, `Split into ${items.length} items`));
|
|
894
|
+
}
|
|
895
|
+
if (duplicates) derivations.push(derivation('listDeduplicated', text, items, `Dropped ${duplicates} repeated item(s)`));
|
|
896
|
+
const max = options.max;
|
|
897
|
+
if (max !== undefined && items.length > max) {
|
|
898
|
+
const kept = items.slice(0, max);
|
|
899
|
+
derivations.push(derivation('truncated', text, kept, `Kept the first ${max} items`, true));
|
|
900
|
+
return readValue(kept, derivations);
|
|
901
|
+
}
|
|
902
|
+
return readValue(items, derivations);
|
|
903
|
+
}
|
|
904
|
+
/** A JSON cell parsed; an object or array from a JSON file passes through. */ export function deriveJson(raw) {
|
|
905
|
+
if (raw !== null && typeof raw === 'object') return readValue(raw);
|
|
906
|
+
const text = cellText(raw);
|
|
907
|
+
if (!text) return blankValue();
|
|
908
|
+
try {
|
|
909
|
+
return readValue(JSON.parse(text));
|
|
910
|
+
} catch (unused) {
|
|
911
|
+
return unreadable('invalidJson', 'Not valid JSON.');
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
/** A cell read as the field it was mapped to. */ export function deriveTransferCell(field, raw, options = {}) {
|
|
915
|
+
switch(field.type){
|
|
916
|
+
case 'email':
|
|
917
|
+
return deriveEmail(raw);
|
|
918
|
+
case 'phone':
|
|
919
|
+
return derivePhone(raw, options.phone);
|
|
920
|
+
case 'url':
|
|
921
|
+
return deriveUrl(raw);
|
|
922
|
+
case 'number':
|
|
923
|
+
return deriveNumber(raw, options.number);
|
|
924
|
+
case 'integer':
|
|
925
|
+
return deriveInteger(raw, options.number);
|
|
926
|
+
case 'currency':
|
|
927
|
+
return deriveCurrency(raw, options.currency);
|
|
928
|
+
case 'percent':
|
|
929
|
+
return derivePercent(raw, options.percent);
|
|
930
|
+
case 'boolean':
|
|
931
|
+
return deriveBoolean(raw);
|
|
932
|
+
case 'date':
|
|
933
|
+
return deriveDate(raw, options.date);
|
|
934
|
+
case 'datetime':
|
|
935
|
+
var _options_dateTime;
|
|
936
|
+
return deriveDateTime(raw, (_options_dateTime = options.dateTime) != null ? _options_dateTime : options.date);
|
|
937
|
+
case 'multiPicklist':
|
|
938
|
+
return splitTransferList(raw, options.list);
|
|
939
|
+
case 'tags':
|
|
940
|
+
return splitTransferList(raw, _extends({}, options.list, {
|
|
941
|
+
lowercase: true
|
|
942
|
+
}));
|
|
943
|
+
case 'list':
|
|
944
|
+
return splitTransferList(raw, options.list);
|
|
945
|
+
case 'address':
|
|
946
|
+
return parseAddressLine(raw);
|
|
947
|
+
case 'json':
|
|
948
|
+
return deriveJson(raw);
|
|
949
|
+
case 'longText':
|
|
950
|
+
return deriveText(raw, {
|
|
951
|
+
maxLength: field.maxLength,
|
|
952
|
+
multiline: true
|
|
953
|
+
});
|
|
954
|
+
case 'picklist':
|
|
955
|
+
case 'lookup':
|
|
956
|
+
case 'text':
|
|
957
|
+
default:
|
|
958
|
+
return deriveText(raw, {
|
|
959
|
+
maxLength: field.maxLength
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* A mapped row read as its fields. `cells` is field id → raw cell (from
|
|
965
|
+
* {@link mapTransferRow} or a JSON object); a field the catalog does not
|
|
966
|
+
* know is ignored. `fieldOptions` overrides `options` for one field — the
|
|
967
|
+
* date order a person chose for that column, say.
|
|
968
|
+
*/ export function deriveTransferRow(fields, cells, options = {}, fieldOptions = {}) {
|
|
969
|
+
const row = {
|
|
970
|
+
values: {},
|
|
971
|
+
derivations: [],
|
|
972
|
+
problems: []
|
|
973
|
+
};
|
|
974
|
+
for (const [fieldId, raw] of Object.entries(cells)){
|
|
975
|
+
const field = fields.get(fieldId);
|
|
976
|
+
if (!field) continue;
|
|
977
|
+
const own = fieldOptions[fieldId];
|
|
978
|
+
const result = deriveTransferCell(field, raw, own ? _extends({}, options, own) : options);
|
|
979
|
+
if (!result.ok) {
|
|
980
|
+
row.problems.push(_extends({
|
|
981
|
+
fieldId,
|
|
982
|
+
raw: cellText(raw)
|
|
983
|
+
}, result.problem));
|
|
984
|
+
continue;
|
|
985
|
+
}
|
|
986
|
+
row.values[fieldId] = result.value;
|
|
987
|
+
for (const entry of result.derivations)row.derivations.push(_extends({
|
|
988
|
+
fieldId
|
|
989
|
+
}, entry));
|
|
990
|
+
}
|
|
991
|
+
return row;
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* One line's cells under a column → field mapping, as field id → raw cell.
|
|
995
|
+
* Every mapped column is present, blank or not, so a blank cell can mean
|
|
996
|
+
* "clear" when the person chose that.
|
|
997
|
+
*/ export function mapTransferRow(cells, mapping) {
|
|
998
|
+
const mapped = {};
|
|
999
|
+
for (const [indexText, fieldId] of Object.entries(mapping)){
|
|
1000
|
+
var _cells_Number;
|
|
1001
|
+
if (!fieldId) continue;
|
|
1002
|
+
mapped[fieldId] = (_cells_Number = cells[Number(indexText)]) != null ? _cells_Number : '';
|
|
1003
|
+
}
|
|
1004
|
+
return mapped;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
//# sourceMappingURL=derive.js.map
|