@nmshd/runtime 2.2.0 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/buildInformation.js +5 -5
  2. package/dist/events/EventProxy.js +6 -2
  3. package/dist/events/EventProxy.js.map +1 -1
  4. package/dist/events/consumption/OutgoingRequestCreatedAndCompletedEvent.d.ts +6 -0
  5. package/dist/events/consumption/OutgoingRequestCreatedAndCompletedEvent.js +14 -0
  6. package/dist/events/consumption/OutgoingRequestCreatedAndCompletedEvent.js.map +1 -0
  7. package/dist/events/consumption/index.d.ts +1 -0
  8. package/dist/events/consumption/index.js +1 -0
  9. package/dist/events/consumption/index.js.map +1 -1
  10. package/dist/extensibility/facades/consumption/OutgoingRequestsFacade.d.ts +4 -4
  11. package/dist/extensibility/facades/consumption/OutgoingRequestsFacade.js +5 -5
  12. package/dist/extensibility/facades/consumption/OutgoingRequestsFacade.js.map +1 -1
  13. package/dist/modules/RequestModule.d.ts +3 -1
  14. package/dist/modules/RequestModule.js +26 -10
  15. package/dist/modules/RequestModule.js.map +1 -1
  16. package/dist/useCases/common/Schemas.d.ts +1 -1
  17. package/dist/useCases/common/Schemas.js +18 -7
  18. package/dist/useCases/common/Schemas.js.map +1 -1
  19. package/dist/useCases/consumption/requests/CompleteOutgoingRequest.js.map +1 -1
  20. package/dist/useCases/consumption/requests/CreateAndCompleteOutgoingRequestFromRelationshipCreationChange.d.ts +9 -7
  21. package/dist/useCases/consumption/requests/CreateAndCompleteOutgoingRequestFromRelationshipCreationChange.js +23 -15
  22. package/dist/useCases/consumption/requests/CreateAndCompleteOutgoingRequestFromRelationshipCreationChange.js.map +1 -1
  23. package/dist/useCases/transport/relationshipTemplates/CreateOwnRelationshipTemplate.d.ts +4 -1
  24. package/dist/useCases/transport/relationshipTemplates/CreateOwnRelationshipTemplate.js +24 -1
  25. package/dist/useCases/transport/relationshipTemplates/CreateOwnRelationshipTemplate.js.map +1 -1
  26. package/lib-web/nmshd.runtime.js +1565 -1454
  27. package/lib-web/nmshd.runtime.js.map +1 -1
  28. package/lib-web/nmshd.runtime.min.js +3 -3
  29. package/lib-web/nmshd.runtime.min.js.map +1 -1
  30. package/package.json +7 -7
@@ -466,11 +466,11 @@ const content_1 = __webpack_require__(/*! @nmshd/content */ "@nmshd/content");
466
466
  const crypto_1 = __webpack_require__(/*! @nmshd/crypto */ "@nmshd/crypto");
467
467
  const transport_1 = __webpack_require__(/*! @nmshd/transport */ "@nmshd/transport");
468
468
  exports.buildInformation = {
469
- version: "2.2.0",
470
- build: "133",
471
- date: "2022-12-05T13:59:01+00:00",
472
- commit: "027cf5cd12fd1dc4afe025cf05ffdf1c7e606f46",
473
- dependencies: {"@js-soft/docdb-querytranslator":"1.1.0","@js-soft/logging-abstractions":"1.0.0","@js-soft/ts-serval":"2.0.5","@js-soft/ts-utils":"^2.3.0","@nmshd/consumption":"2.3.0","@nmshd/content":"2.1.2","@nmshd/crypto":"2.0.3","@nmshd/transport":"2.0.0","ajv":"^8.11.2","ajv-errors":"^3.0.0","ajv-formats":"^2.1.1","json-stringify-safe":"^5.0.1","luxon":"^3.1.0","qrcode":"1.5.1","reflect-metadata":"0.1.13","ts-simple-nameof":"1.3.1","typescript-ioc":"3.2.2"},
469
+ version: "2.2.2",
470
+ build: "135",
471
+ date: "2022-12-08T13:35:57+00:00",
472
+ commit: "9720f8b9f9a4315610eb5389975687fdca3efd62",
473
+ dependencies: {"@js-soft/docdb-querytranslator":"1.1.0","@js-soft/logging-abstractions":"1.0.0","@js-soft/ts-serval":"2.0.5","@js-soft/ts-utils":"^2.3.0","@nmshd/consumption":"3.0.1","@nmshd/content":"2.1.2","@nmshd/crypto":"2.0.3","@nmshd/transport":"2.0.0","ajv":"^8.11.2","ajv-errors":"^3.0.0","ajv-formats":"^2.1.1","json-stringify-safe":"^5.0.1","luxon":"^3.1.1","qrcode":"1.5.1","reflect-metadata":"0.1.13","ts-simple-nameof":"1.3.1","typescript-ioc":"3.2.2"},
474
474
  libraries: {
475
475
  serval: ts_serval_1.buildInformation,
476
476
  consumption: consumption_1.buildInformation,
@@ -2480,8 +2480,12 @@ class EventProxy {
2480
2480
  this.subscribeToSourceEvent(consumption.OutgoingRequestCreatedEvent, (event) => {
2481
2481
  this.targetEventBus.publish(new consumption_1.OutgoingRequestCreatedEvent(event.eventTargetAddress, useCases_1.RequestMapper.toLocalRequestDTO(event.data)));
2482
2482
  });
2483
- this.subscribeToSourceEvent(consumption.OutgoingRequestFromRelationshipCreationChangeCreatedAndCompletedEvent, (event) => {
2484
- this.targetEventBus.publish(new consumption_1.OutgoingRequestFromRelationshipCreationChangeCreatedAndCompletedEvent(event.eventTargetAddress, useCases_1.RequestMapper.toLocalRequestDTO(event.data)));
2483
+ this.subscribeToSourceEvent(consumption.OutgoingRequestCreatedAndCompletedEvent, (event) => {
2484
+ const mappedRequest = useCases_1.RequestMapper.toLocalRequestDTO(event.data);
2485
+ this.targetEventBus.publish(new consumption_1.OutgoingRequestCreatedAndCompletedEvent(event.eventTargetAddress, mappedRequest));
2486
+ if (event.data.response?.source?.type === "RelationshipChange") {
2487
+ this.targetEventBus.publish(new consumption_1.OutgoingRequestFromRelationshipCreationChangeCreatedAndCompletedEvent(event.eventTargetAddress, mappedRequest));
2488
+ }
2485
2489
  });
2486
2490
  this.subscribeToSourceEvent(consumption.OutgoingRequestStatusChangedEvent, (event) => {
2487
2491
  this.targetEventBus.publish(new consumption_1.OutgoingRequestStatusChangedEvent(event.eventTargetAddress, {
@@ -2741,6 +2745,30 @@ var MessageProcessedResult;
2741
2745
 
2742
2746
  /***/ }),
2743
2747
 
2748
+ /***/ "./dist/events/consumption/OutgoingRequestCreatedAndCompletedEvent.js":
2749
+ /*!****************************************************************************!*\
2750
+ !*** ./dist/events/consumption/OutgoingRequestCreatedAndCompletedEvent.js ***!
2751
+ \****************************************************************************/
2752
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
2753
+
2754
+ "use strict";
2755
+
2756
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2757
+ exports.OutgoingRequestCreatedAndCompletedEvent = void 0;
2758
+ const DataEvent_1 = __webpack_require__(/*! ../DataEvent */ "./dist/events/DataEvent.js");
2759
+ class OutgoingRequestCreatedAndCompletedEvent extends DataEvent_1.DataEvent {
2760
+ constructor(eventTargetAddress, data) {
2761
+ super(OutgoingRequestCreatedAndCompletedEvent.namespace, eventTargetAddress, data);
2762
+ if (!data.isOwn)
2763
+ throw new Error("Cannot create this event for an incoming Request");
2764
+ }
2765
+ }
2766
+ exports.OutgoingRequestCreatedAndCompletedEvent = OutgoingRequestCreatedAndCompletedEvent;
2767
+ OutgoingRequestCreatedAndCompletedEvent.namespace = "consumption.outgoingRequestCreatedAndCompleted";
2768
+ //# sourceMappingURL=OutgoingRequestCreatedAndCompletedEvent.js.map
2769
+
2770
+ /***/ }),
2771
+
2744
2772
  /***/ "./dist/events/consumption/OutgoingRequestCreatedEvent.js":
2745
2773
  /*!****************************************************************!*\
2746
2774
  !*** ./dist/events/consumption/OutgoingRequestCreatedEvent.js ***!
@@ -2923,6 +2951,7 @@ __exportStar(__webpack_require__(/*! ./IncomingRequestReceivedEvent */ "./dist/e
2923
2951
  __exportStar(__webpack_require__(/*! ./IncomingRequestStatusChangedEvent */ "./dist/events/consumption/IncomingRequestStatusChangedEvent.js"), exports);
2924
2952
  __exportStar(__webpack_require__(/*! ./MailReceivedEvent */ "./dist/events/consumption/MailReceivedEvent.js"), exports);
2925
2953
  __exportStar(__webpack_require__(/*! ./MessageProcessedEvent */ "./dist/events/consumption/MessageProcessedEvent.js"), exports);
2954
+ __exportStar(__webpack_require__(/*! ./OutgoingRequestCreatedAndCompletedEvent */ "./dist/events/consumption/OutgoingRequestCreatedAndCompletedEvent.js"), exports);
2926
2955
  __exportStar(__webpack_require__(/*! ./OutgoingRequestCreatedEvent */ "./dist/events/consumption/OutgoingRequestCreatedEvent.js"), exports);
2927
2956
  __exportStar(__webpack_require__(/*! ./OutgoingRequestFromRelationshipCreationChangeCreatedAndCompletedEvent */ "./dist/events/consumption/OutgoingRequestFromRelationshipCreationChangeCreatedAndCompletedEvent.js"), exports);
2928
2957
  __exportStar(__webpack_require__(/*! ./OutgoingRequestStatusChangedEvent */ "./dist/events/consumption/OutgoingRequestStatusChangedEvent.js"), exports);
@@ -3819,11 +3848,11 @@ exports.OutgoingRequestsFacade = void 0;
3819
3848
  const typescript_ioc_1 = __webpack_require__(/*! typescript-ioc */ "./node_modules/typescript-ioc/dist/typescript-ioc.js");
3820
3849
  const useCases_1 = __webpack_require__(/*! ../../../useCases */ "./dist/useCases/index.js");
3821
3850
  let OutgoingRequestsFacade = class OutgoingRequestsFacade {
3822
- constructor(canCreateUseCase, createUseCase, sentUseCase, createAndCompleteFromRelationshipCreationChangeUseCase, completeUseCase, getRequestUseCase, getRequestsUseCase, discardRequestUseCase) {
3851
+ constructor(canCreateUseCase, createUseCase, sentUseCase, createAndCompleteFromRelationshipTemplateResponseUseCase, completeUseCase, getRequestUseCase, getRequestsUseCase, discardRequestUseCase) {
3823
3852
  this.canCreateUseCase = canCreateUseCase;
3824
3853
  this.createUseCase = createUseCase;
3825
3854
  this.sentUseCase = sentUseCase;
3826
- this.createAndCompleteFromRelationshipCreationChangeUseCase = createAndCompleteFromRelationshipCreationChangeUseCase;
3855
+ this.createAndCompleteFromRelationshipTemplateResponseUseCase = createAndCompleteFromRelationshipTemplateResponseUseCase;
3827
3856
  this.completeUseCase = completeUseCase;
3828
3857
  this.getRequestUseCase = getRequestUseCase;
3829
3858
  this.getRequestsUseCase = getRequestsUseCase;
@@ -3835,8 +3864,8 @@ let OutgoingRequestsFacade = class OutgoingRequestsFacade {
3835
3864
  async create(request) {
3836
3865
  return await this.createUseCase.execute(request);
3837
3866
  }
3838
- async createAndCompleteFromRelationshipCreationChange(request) {
3839
- return await this.createAndCompleteFromRelationshipCreationChangeUseCase.execute(request);
3867
+ async createAndCompleteFromRelationshipTemplateResponse(request) {
3868
+ return await this.createAndCompleteFromRelationshipTemplateResponseUseCase.execute(request);
3840
3869
  }
3841
3870
  async sent(request) {
3842
3871
  return await this.sentUseCase.execute(request);
@@ -3866,7 +3895,7 @@ OutgoingRequestsFacade = __decorate([
3866
3895
  __metadata("design:paramtypes", [useCases_1.CanCreateOutgoingRequestUseCase,
3867
3896
  useCases_1.CreateOutgoingRequestUseCase,
3868
3897
  useCases_1.SentOutgoingRequestUseCase,
3869
- useCases_1.CreateAndCompleteOutgoingRequestFromRelationshipCreationChangeUseCase,
3898
+ useCases_1.CreateAndCompleteOutgoingRequestFromRelationshipTemplateResponseUseCase,
3870
3899
  useCases_1.CompleteOutgoingRequestUseCase,
3871
3900
  useCases_1.GetOutgoingRequestUseCase,
3872
3901
  useCases_1.GetOutgoingRequestsUseCase,
@@ -5088,6 +5117,7 @@ class RequestModule extends RuntimeModule_1.RuntimeModule {
5088
5117
  break;
5089
5118
  case "Response":
5090
5119
  const receivedResponse = message.content;
5120
+ // TODO: create the Response with createAndCompleteFromRelationshipTemplateResponse in case of a Request from Template
5091
5121
  const result = await services.consumptionServices.outgoingRequests.complete({ receivedResponse, messageId: message.id });
5092
5122
  if (result.isError) {
5093
5123
  this.logger.error(`Could not complete outgoing request for message id ${message.id} due to ${result.error}. Root error:`, result.error);
@@ -5116,9 +5146,9 @@ class RequestModule extends RuntimeModule_1.RuntimeModule {
5116
5146
  this.logger.error(`Could not receive request ${request.id}. Root error:`, receivedRequestResult.error);
5117
5147
  return false;
5118
5148
  }
5119
- const checkPrerequitesResult = await services.consumptionServices.incomingRequests.checkPrerequisites({ requestId: receivedRequestResult.value.id });
5120
- if (checkPrerequitesResult.isError) {
5121
- this.logger.error(`Could not check prerequisites for request ${request.id}. Root error:`, checkPrerequitesResult.error);
5149
+ const checkPrerequisitesResult = await services.consumptionServices.incomingRequests.checkPrerequisites({ requestId: receivedRequestResult.value.id });
5150
+ if (checkPrerequisitesResult.isError) {
5151
+ this.logger.error(`Could not check prerequisites for request ${request.id}. Root error:`, checkPrerequisitesResult.error);
5122
5152
  return false;
5123
5153
  }
5124
5154
  return true;
@@ -5129,7 +5159,7 @@ class RequestModule extends RuntimeModule_1.RuntimeModule {
5129
5159
  const request = event.data.request;
5130
5160
  switch (request.source.type) {
5131
5161
  case "RelationshipTemplate":
5132
- await this.handleIncomingRequestDecidedForRelationship(event);
5162
+ await this.handleIncomingRequestDecidedForRelationshipTemplate(event);
5133
5163
  break;
5134
5164
  case "Message":
5135
5165
  await this.handleIncomingRequestDecidedForMessage(event);
@@ -5138,10 +5168,20 @@ class RequestModule extends RuntimeModule_1.RuntimeModule {
5138
5168
  throw new Error(`Cannot handle source.type '${request.source.type}'.`);
5139
5169
  }
5140
5170
  }
5141
- async handleIncomingRequestDecidedForRelationship(event) {
5171
+ async handleIncomingRequestDecidedForRelationshipTemplate(event) {
5142
5172
  const request = event.data.request;
5143
- const templateId = request.source.reference;
5144
5173
  const services = await this.runtime.getServices(event.eventTargetAddress);
5174
+ const activeRelationshipsToPeer = (await services.transportServices.relationships.getRelationships({ query: { peer: event.data.request.peer, status: types_1.RelationshipStatus.Active } })).value;
5175
+ if (activeRelationshipsToPeer.length === 0) {
5176
+ await this.respondToRequestViaRelationship(request, event.eventTargetAddress);
5177
+ }
5178
+ else {
5179
+ await this.respondToRequestViaMessage(request, event.eventTargetAddress);
5180
+ }
5181
+ }
5182
+ async respondToRequestViaRelationship(request, currentIdentity) {
5183
+ const services = await this.runtime.getServices(currentIdentity);
5184
+ const templateId = request.source.reference;
5145
5185
  if (request.response.content.result === content_1.ResponseResult.Rejected) {
5146
5186
  await services.consumptionServices.incomingRequests.complete({ requestId: request.id });
5147
5187
  return;
@@ -5162,10 +5202,9 @@ class RequestModule extends RuntimeModule_1.RuntimeModule {
5162
5202
  return;
5163
5203
  }
5164
5204
  }
5165
- async handleIncomingRequestDecidedForMessage(event) {
5166
- const request = event.data.request;
5205
+ async respondToRequestViaMessage(request, currentIdentity) {
5167
5206
  const requestId = request.id;
5168
- const services = await this.runtime.getServices(event.eventTargetAddress);
5207
+ const services = await this.runtime.getServices(currentIdentity);
5169
5208
  const sendMessageResult = await services.transportServices.messages.sendMessage({
5170
5209
  recipients: [request.peer],
5171
5210
  content: request.response.content
@@ -5183,6 +5222,9 @@ class RequestModule extends RuntimeModule_1.RuntimeModule {
5183
5222
  return;
5184
5223
  }
5185
5224
  }
5225
+ async handleIncomingRequestDecidedForMessage(event) {
5226
+ await this.respondToRequestViaMessage(event.data.request, event.eventTargetAddress);
5227
+ }
5186
5228
  async handleRelationshipChangedEvent(event) {
5187
5229
  // only trigger for new relationships that were created from an own template
5188
5230
  const createdRelationship = event.data;
@@ -5199,7 +5241,10 @@ class RequestModule extends RuntimeModule_1.RuntimeModule {
5199
5241
  // do not trigger for creation changes without the correct content type
5200
5242
  if (relationshipCreationChange.request.content["@type"] !== "RelationshipCreationChangeRequestContent")
5201
5243
  return;
5202
- const result = await services.consumptionServices.outgoingRequests.createAndCompleteFromRelationshipCreationChange({ templateId, relationshipChangeId });
5244
+ const result = await services.consumptionServices.outgoingRequests.createAndCompleteFromRelationshipTemplateResponse({
5245
+ templateId,
5246
+ responseSourceId: relationshipChangeId
5247
+ });
5203
5248
  if (result.isError) {
5204
5249
  this.logger.error(`Could not create and complete request for templateId '${templateId}' and changeId '${relationshipChangeId}'. Root error:`, result.error);
5205
5250
  return;
@@ -6120,7 +6165,7 @@ exports.JsonSchema = JsonSchema;
6120
6165
  "use strict";
6121
6166
 
6122
6167
  Object.defineProperty(exports, "__esModule", ({ value: true }));
6123
- exports.CreateIdentityChallengeRequest = exports.CreateRelationshipChallengeRequest = exports.SyncEverythingRequest = exports.DownloadAttachmentRequest = exports.SyncDatawalletRequest = exports.RegisterPushNotificationTokenRequest = exports.LoadItemFromTruncatedReferenceRequest = exports.DownloadFileRequest = exports.UpdateSettingRequest = exports.GetSettingsRequest = exports.GetSettingRequest = exports.DeleteSettingRequest = exports.CreateSettingRequest = exports.UpdateDraftRequest = exports.GetDraftsRequest = exports.GetDraftRequest = exports.DeleteDraftRequest = exports.CreateDraftRequest = exports.UpdateAttributeRequest = exports.SucceedAttributeRequest = exports.ShareAttributeRequest = exports.SentOutgoingRequestRequest = exports.RequireManualDecisionOfIncomingRequestRequest = exports.ReceivedIncomingRequestRequest = exports.GetOutgoingRequestsRequest = exports.GetOutgoingRequestRequest = exports.GetIncomingRequestsRequest = exports.GetIncomingRequestRequest = exports.DiscardOutgoingRequestRequest = exports.CreateOutgoingRequestRequest = exports.CreateAndCompleteOutgoingRequestFromRelationshipCreationChangeRequest = exports.CompleteOutgoingRequestRequest = exports.CompleteIncomingRequestRequest = exports.CheckPrerequisitesOfIncomingRequestRequest = exports.RejectIncomingRequestRequest = exports.CanCreateOutgoingRequestRequest = exports.AcceptIncomingRequestRequest = exports.GetSharedToPeerAttributesRequest = exports.GetPeerAttributesRequest = exports.GetAttributesRequest = exports.GetAttributeRequest = exports.ExecuteThirdPartyRelationshipAttributeQueryRequest = exports.ExecuteRelationshipAttributeQueryRequest = exports.ExecuteIdentityAttributeQueryRequest = exports.DeleteAttributeRequest = exports.CreateSharedAttributeCopyRequest = exports.CreateAttributeRequest = exports.GetAttributeListenerRequest = exports.LoadPeerTokenAnonymousByTruncatedReferenceRequest = exports.LoadPeerTokenAnonymousByIdAndKeyRequest = void 0;
6168
+ exports.CreateIdentityChallengeRequest = exports.CreateRelationshipChallengeRequest = exports.SyncEverythingRequest = exports.DownloadAttachmentRequest = exports.SyncDatawalletRequest = exports.RegisterPushNotificationTokenRequest = exports.LoadItemFromTruncatedReferenceRequest = exports.DownloadFileRequest = exports.UpdateSettingRequest = exports.GetSettingsRequest = exports.GetSettingRequest = exports.DeleteSettingRequest = exports.CreateSettingRequest = exports.UpdateDraftRequest = exports.GetDraftsRequest = exports.GetDraftRequest = exports.DeleteDraftRequest = exports.CreateDraftRequest = exports.UpdateAttributeRequest = exports.SucceedAttributeRequest = exports.ShareAttributeRequest = exports.SentOutgoingRequestRequest = exports.RequireManualDecisionOfIncomingRequestRequest = exports.ReceivedIncomingRequestRequest = exports.GetOutgoingRequestsRequest = exports.GetOutgoingRequestRequest = exports.GetIncomingRequestsRequest = exports.GetIncomingRequestRequest = exports.DiscardOutgoingRequestRequest = exports.CreateOutgoingRequestRequest = exports.CreateAndCompleteOutgoingRequestFromRelationshipTemplateResponseRequest = exports.CompleteOutgoingRequestRequest = exports.CompleteIncomingRequestRequest = exports.CheckPrerequisitesOfIncomingRequestRequest = exports.RejectIncomingRequestRequest = exports.CanCreateOutgoingRequestRequest = exports.AcceptIncomingRequestRequest = exports.GetSharedToPeerAttributesRequest = exports.GetPeerAttributesRequest = exports.GetAttributesRequest = exports.GetAttributeRequest = exports.ExecuteThirdPartyRelationshipAttributeQueryRequest = exports.ExecuteRelationshipAttributeQueryRequest = exports.ExecuteIdentityAttributeQueryRequest = exports.DeleteAttributeRequest = exports.CreateSharedAttributeCopyRequest = exports.CreateAttributeRequest = exports.GetAttributeListenerRequest = exports.LoadPeerTokenAnonymousByTruncatedReferenceRequest = exports.LoadPeerTokenAnonymousByIdAndKeyRequest = void 0;
6124
6169
  exports.LoadPeerTokenRequest = exports.LoadPeerTokenViaSecretRequest = exports.LoadPeerTokenViaReferenceRequest = exports.GetTokensRequest = exports.GetTokenRequest = exports.GetQRCodeForTokenRequest = exports.CreateOwnTokenRequest = exports.LoadPeerRelationshipTemplateRequest = exports.LoadPeerRelationshipTemplateViaReferenceRequest = exports.LoadPeerRelationshipTemplateViaSecretRequest = exports.GetRelationshipTemplatesRequest = exports.GetRelationshipTemplateRequest = exports.CreateTokenQrCodeForOwnTemplateRequest = exports.CreateTokenForOwnTemplateRequest = exports.CreateQrCodeForOwnTemplateRequest = exports.CreateOwnRelationshipTemplateRequest = exports.RevokeRelationshipChangeRequest = exports.RejectRelationshipChangeRequest = exports.GetRelationshipsRequest = exports.GetRelationshipByAddressRequest = exports.GetRelationshipRequest = exports.GetAttributesForRelationshipRequest = exports.CreateRelationshipRequest = exports.AcceptRelationshipChangeRequest = exports.SendMessageRequest = exports.GetMessagesRequest = exports.GetMessageRequest = exports.GetAttachmentMetadataRequest = exports.CheckIdentityRequest = exports.UploadOwnFileValidatableRequest = exports.UploadOwnFileRequest = exports.GetOrLoadFileRequest = exports.GetOrLoadFileViaReferenceRequest = exports.GetOrLoadFileViaSecretRequest = exports.GetFilesRequest = exports.GetFileRequest = exports.CreateTokenQrCodeForFileRequest = exports.CreateTokenForFileRequest = exports.CreateQrCodeForFileRequest = exports.UpdateDeviceRequest = exports.GetDeviceOnboardingInfoRequest = exports.GetDeviceRequest = exports.DeleteDeviceRequest = exports.CreateDeviceOnboardingTokenRequest = exports.CreateDeviceRequest = exports.ValidateChallengeRequest = exports.CreateChallengeRequest = exports.CreateDeviceChallengeRequest = void 0;
6125
6170
  exports.LoadPeerTokenAnonymousByIdAndKeyRequest = {
6126
6171
  "$schema": "http://json-schema.org/draft-07/schema#",
@@ -14370,23 +14415,30 @@ exports.CompleteOutgoingRequestRequest = {
14370
14415
  }
14371
14416
  }
14372
14417
  };
14373
- exports.CreateAndCompleteOutgoingRequestFromRelationshipCreationChangeRequest = {
14418
+ exports.CreateAndCompleteOutgoingRequestFromRelationshipTemplateResponseRequest = {
14374
14419
  "$schema": "http://json-schema.org/draft-07/schema#",
14375
- "$ref": "#/definitions/CreateAndCompleteOutgoingRequestFromRelationshipCreationChangeRequest",
14420
+ "$ref": "#/definitions/CreateAndCompleteOutgoingRequestFromRelationshipTemplateResponseRequest",
14376
14421
  "definitions": {
14377
- "CreateAndCompleteOutgoingRequestFromRelationshipCreationChangeRequest": {
14422
+ "CreateAndCompleteOutgoingRequestFromRelationshipTemplateResponseRequest": {
14378
14423
  "type": "object",
14379
14424
  "properties": {
14380
14425
  "templateId": {
14381
14426
  "$ref": "#/definitions/RelationshipTemplateIdString"
14382
14427
  },
14383
- "relationshipChangeId": {
14384
- "$ref": "#/definitions/RelationshipChangeIdString"
14428
+ "responseSourceId": {
14429
+ "anyOf": [
14430
+ {
14431
+ "$ref": "#/definitions/RelationshipChangeIdString"
14432
+ },
14433
+ {
14434
+ "$ref": "#/definitions/MessageIdString"
14435
+ }
14436
+ ]
14385
14437
  }
14386
14438
  },
14387
14439
  "required": [
14388
14440
  "templateId",
14389
- "relationshipChangeId"
14441
+ "responseSourceId"
14390
14442
  ],
14391
14443
  "additionalProperties": false
14392
14444
  },
@@ -14397,6 +14449,10 @@ exports.CreateAndCompleteOutgoingRequestFromRelationshipCreationChangeRequest =
14397
14449
  "RelationshipChangeIdString": {
14398
14450
  "type": "string",
14399
14451
  "pattern": "RCH[A-Za-z0-9]{17}"
14452
+ },
14453
+ "MessageIdString": {
14454
+ "type": "string",
14455
+ "pattern": "MSG[A-Za-z0-9]{17}"
14400
14456
  }
14401
14457
  }
14402
14458
  };
@@ -28380,47 +28436,55 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
28380
28436
  return function (target, key) { decorator(target, key, paramIndex); }
28381
28437
  };
28382
28438
  Object.defineProperty(exports, "__esModule", ({ value: true }));
28383
- exports.CreateAndCompleteOutgoingRequestFromRelationshipCreationChangeUseCase = void 0;
28439
+ exports.CreateAndCompleteOutgoingRequestFromRelationshipTemplateResponseUseCase = void 0;
28384
28440
  const ts_utils_1 = __webpack_require__(/*! @js-soft/ts-utils */ "./node_modules/@js-soft/ts-utils/dist/index.js");
28385
28441
  const consumption_1 = __webpack_require__(/*! @nmshd/consumption */ "@nmshd/consumption");
28386
28442
  const transport_1 = __webpack_require__(/*! @nmshd/transport */ "@nmshd/transport");
28387
28443
  const typescript_ioc_1 = __webpack_require__(/*! typescript-ioc */ "./node_modules/typescript-ioc/dist/typescript-ioc.js");
28388
28444
  const common_1 = __webpack_require__(/*! ../../common */ "./dist/useCases/common/index.js");
28389
28445
  const RequestMapper_1 = __webpack_require__(/*! ./RequestMapper */ "./dist/useCases/consumption/requests/RequestMapper.js");
28390
- let CreateAndCompleteOutgoingRequestFromRelationshipCreationChangeUseCase = class CreateAndCompleteOutgoingRequestFromRelationshipCreationChangeUseCase extends common_1.UseCase {
28391
- constructor(outgoingRequestsController, relationshipController, relationshipTemplateController) {
28446
+ let CreateAndCompleteOutgoingRequestFromRelationshipTemplateResponseUseCase = class CreateAndCompleteOutgoingRequestFromRelationshipTemplateResponseUseCase extends common_1.UseCase {
28447
+ constructor(outgoingRequestsController, relationshipController, relationshipTemplateController, messageController) {
28392
28448
  super();
28393
28449
  this.outgoingRequestsController = outgoingRequestsController;
28394
28450
  this.relationshipController = relationshipController;
28395
28451
  this.relationshipTemplateController = relationshipTemplateController;
28452
+ this.messageController = messageController;
28396
28453
  }
28397
28454
  async executeInternal(request) {
28398
28455
  const template = await this.relationshipTemplateController.getRelationshipTemplate(transport_1.CoreId.from(request.templateId));
28399
28456
  if (!template) {
28400
28457
  return ts_utils_1.Result.fail(common_1.RuntimeErrors.general.recordNotFound(transport_1.RelationshipTemplate));
28401
28458
  }
28402
- const relationships = await this.relationshipController.getRelationships({ "cache.changes.id": request.relationshipChangeId });
28403
- if (relationships.length === 0) {
28459
+ const responseSource = await this.getResponseSource(request.responseSourceId);
28460
+ if (!responseSource) {
28404
28461
  return ts_utils_1.Result.fail(common_1.RuntimeErrors.general.recordNotFound(transport_1.RelationshipChange));
28405
28462
  }
28406
- const relationship = relationships[0];
28407
- const params = {
28408
- template: template,
28409
- creationChange: relationship.cache.creationChange
28410
- };
28411
- const localRequest = await this.outgoingRequestsController.createFromRelationshipCreationChange(params);
28463
+ const localRequest = await this.outgoingRequestsController.createFromRelationshipTemplateResponse({ template, responseSource });
28412
28464
  return ts_utils_1.Result.ok(RequestMapper_1.RequestMapper.toLocalRequestDTO(localRequest));
28413
28465
  }
28466
+ async getResponseSource(responseSourceId) {
28467
+ if (responseSourceId.startsWith("MSG"))
28468
+ return await this.messageController.getMessage(transport_1.CoreId.from(responseSourceId));
28469
+ const relationships = await this.relationshipController.getRelationships({ "cache.changes.id": responseSourceId });
28470
+ if (relationships.length !== 0) {
28471
+ const relationship = relationships[0];
28472
+ return relationship.cache.creationChange;
28473
+ }
28474
+ return;
28475
+ }
28414
28476
  };
28415
- CreateAndCompleteOutgoingRequestFromRelationshipCreationChangeUseCase = __decorate([
28477
+ CreateAndCompleteOutgoingRequestFromRelationshipTemplateResponseUseCase = __decorate([
28416
28478
  __param(0, typescript_ioc_1.Inject),
28417
28479
  __param(1, typescript_ioc_1.Inject),
28418
28480
  __param(2, typescript_ioc_1.Inject),
28481
+ __param(3, typescript_ioc_1.Inject),
28419
28482
  __metadata("design:paramtypes", [consumption_1.OutgoingRequestsController,
28420
28483
  transport_1.RelationshipsController,
28421
- transport_1.RelationshipTemplateController])
28422
- ], CreateAndCompleteOutgoingRequestFromRelationshipCreationChangeUseCase);
28423
- exports.CreateAndCompleteOutgoingRequestFromRelationshipCreationChangeUseCase = CreateAndCompleteOutgoingRequestFromRelationshipCreationChangeUseCase;
28484
+ transport_1.RelationshipTemplateController,
28485
+ transport_1.MessageController])
28486
+ ], CreateAndCompleteOutgoingRequestFromRelationshipTemplateResponseUseCase);
28487
+ exports.CreateAndCompleteOutgoingRequestFromRelationshipTemplateResponseUseCase = CreateAndCompleteOutgoingRequestFromRelationshipTemplateResponseUseCase;
28424
28488
  //# sourceMappingURL=CreateAndCompleteOutgoingRequestFromRelationshipCreationChange.js.map
28425
28489
 
28426
28490
  /***/ }),
@@ -32464,7 +32528,10 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
32464
32528
  };
32465
32529
  Object.defineProperty(exports, "__esModule", ({ value: true }));
32466
32530
  exports.CreateOwnRelationshipTemplateUseCase = void 0;
32531
+ const ts_serval_1 = __webpack_require__(/*! @js-soft/ts-serval */ "@js-soft/ts-serval");
32467
32532
  const ts_utils_1 = __webpack_require__(/*! @js-soft/ts-utils */ "./node_modules/@js-soft/ts-utils/dist/index.js");
32533
+ const consumption_1 = __webpack_require__(/*! @nmshd/consumption */ "@nmshd/consumption");
32534
+ const content_1 = __webpack_require__(/*! @nmshd/content */ "@nmshd/content");
32468
32535
  const transport_1 = __webpack_require__(/*! @nmshd/transport */ "@nmshd/transport");
32469
32536
  const luxon_1 = __webpack_require__(/*! luxon */ "./node_modules/luxon/build/node/luxon.js");
32470
32537
  const ts_simple_nameof_1 = __webpack_require__(/*! ts-simple-nameof */ "./node_modules/ts-simple-nameof/index.js");
@@ -32490,12 +32557,16 @@ Validator = __decorate([
32490
32557
  __metadata("design:paramtypes", [common_1.SchemaRepository])
32491
32558
  ], Validator);
32492
32559
  let CreateOwnRelationshipTemplateUseCase = class CreateOwnRelationshipTemplateUseCase extends common_1.UseCase {
32493
- constructor(templateController, accountController, validator) {
32560
+ constructor(templateController, accountController, outgoingRequestsController, validator) {
32494
32561
  super(validator);
32495
32562
  this.templateController = templateController;
32496
32563
  this.accountController = accountController;
32564
+ this.outgoingRequestsController = outgoingRequestsController;
32497
32565
  }
32498
32566
  async executeInternal(request) {
32567
+ const validationError = await this.validateRelationshipTemplateContent(request.content);
32568
+ if (validationError)
32569
+ return ts_utils_1.Result.fail(validationError);
32499
32570
  const relationshipTemplate = await this.templateController.sendRelationshipTemplate({
32500
32571
  content: request.content,
32501
32572
  expiresAt: transport_1.CoreDate.from(request.expiresAt),
@@ -32504,13 +32575,29 @@ let CreateOwnRelationshipTemplateUseCase = class CreateOwnRelationshipTemplateUs
32504
32575
  await this.accountController.syncDatawallet();
32505
32576
  return ts_utils_1.Result.ok(RelationshipTemplateMapper_1.RelationshipTemplateMapper.toRelationshipTemplateDTO(relationshipTemplate));
32506
32577
  }
32578
+ async validateRelationshipTemplateContent(content) {
32579
+ const transformedContent = ts_serval_1.Serializable.fromUnknown(content);
32580
+ if (!(transformedContent instanceof content_1.RelationshipTemplateContent))
32581
+ return;
32582
+ const validationResult = await this.outgoingRequestsController.canCreate({ content: transformedContent.onNewRelationship });
32583
+ if (validationResult.isError())
32584
+ return validationResult.error;
32585
+ if (transformedContent.onExistingRelationship) {
32586
+ const validationResult = await this.outgoingRequestsController.canCreate({ content: transformedContent.onExistingRelationship });
32587
+ if (validationResult.isError())
32588
+ return validationResult.error;
32589
+ }
32590
+ return;
32591
+ }
32507
32592
  };
32508
32593
  CreateOwnRelationshipTemplateUseCase = __decorate([
32509
32594
  __param(0, typescript_ioc_1.Inject),
32510
32595
  __param(1, typescript_ioc_1.Inject),
32511
32596
  __param(2, typescript_ioc_1.Inject),
32597
+ __param(3, typescript_ioc_1.Inject),
32512
32598
  __metadata("design:paramtypes", [transport_1.RelationshipTemplateController,
32513
32599
  transport_1.AccountController,
32600
+ consumption_1.OutgoingRequestsController,
32514
32601
  Validator])
32515
32602
  ], CreateOwnRelationshipTemplateUseCase);
32516
32603
  exports.CreateOwnRelationshipTemplateUseCase = CreateOwnRelationshipTemplateUseCase;
@@ -45671,1252 +45758,876 @@ const DATETIME_HUGE_WITH_SECONDS = {
45671
45758
  timeZoneName: l
45672
45759
  };
45673
45760
 
45674
- /*
45675
- This is just a junk drawer, containing anything used across multiple classes.
45676
- Because Luxon is small(ish), this should stay small and we won't worry about splitting
45677
- it up into, say, parsingUtil.js and basicUtil.js and so on. But they are divided up by feature area.
45678
- */
45679
45761
  /**
45680
- * @private
45762
+ * @interface
45681
45763
  */
45682
- // TYPES
45683
-
45684
- function isUndefined(o) {
45685
- return typeof o === "undefined";
45686
- }
45687
- function isNumber(o) {
45688
- return typeof o === "number";
45689
- }
45690
- function isInteger(o) {
45691
- return typeof o === "number" && o % 1 === 0;
45692
- }
45693
- function isString(o) {
45694
- return typeof o === "string";
45695
- }
45696
- function isDate(o) {
45697
- return Object.prototype.toString.call(o) === "[object Date]";
45698
- } // CAPABILITIES
45699
-
45700
- function hasRelative() {
45701
- try {
45702
- return typeof Intl !== "undefined" && !!Intl.RelativeTimeFormat;
45703
- } catch (e) {
45704
- return false;
45705
- }
45706
- } // OBJECTS AND ARRAYS
45707
45764
 
45708
- function maybeArray(thing) {
45709
- return Array.isArray(thing) ? thing : [thing];
45710
- }
45711
- function bestBy(arr, by, compare) {
45712
- if (arr.length === 0) {
45713
- return undefined;
45765
+ class Zone {
45766
+ /**
45767
+ * The type of zone
45768
+ * @abstract
45769
+ * @type {string}
45770
+ */
45771
+ get type() {
45772
+ throw new ZoneIsAbstractError();
45714
45773
  }
45774
+ /**
45775
+ * The name of this zone.
45776
+ * @abstract
45777
+ * @type {string}
45778
+ */
45715
45779
 
45716
- return arr.reduce((best, next) => {
45717
- const pair = [by(next), next];
45718
45780
 
45719
- if (!best) {
45720
- return pair;
45721
- } else if (compare(best[0], pair[0]) === best[0]) {
45722
- return best;
45723
- } else {
45724
- return pair;
45725
- }
45726
- }, null)[1];
45727
- }
45728
- function pick(obj, keys) {
45729
- return keys.reduce((a, k) => {
45730
- a[k] = obj[k];
45731
- return a;
45732
- }, {});
45733
- }
45734
- function hasOwnProperty(obj, prop) {
45735
- return Object.prototype.hasOwnProperty.call(obj, prop);
45736
- } // NUMBERS AND STRINGS
45781
+ get name() {
45782
+ throw new ZoneIsAbstractError();
45783
+ }
45737
45784
 
45738
- function integerBetween(thing, bottom, top) {
45739
- return isInteger(thing) && thing >= bottom && thing <= top;
45740
- } // x % n but takes the sign of n instead of x
45785
+ get ianaName() {
45786
+ return this.name;
45787
+ }
45788
+ /**
45789
+ * Returns whether the offset is known to be fixed for the whole year.
45790
+ * @abstract
45791
+ * @type {boolean}
45792
+ */
45741
45793
 
45742
- function floorMod(x, n) {
45743
- return x - n * Math.floor(x / n);
45744
- }
45745
- function padStart(input, n = 2) {
45746
- const isNeg = input < 0;
45747
- let padded;
45748
45794
 
45749
- if (isNeg) {
45750
- padded = "-" + ("" + -input).padStart(n, "0");
45751
- } else {
45752
- padded = ("" + input).padStart(n, "0");
45795
+ get isUniversal() {
45796
+ throw new ZoneIsAbstractError();
45753
45797
  }
45798
+ /**
45799
+ * Returns the offset's common name (such as EST) at the specified timestamp
45800
+ * @abstract
45801
+ * @param {number} ts - Epoch milliseconds for which to get the name
45802
+ * @param {Object} opts - Options to affect the format
45803
+ * @param {string} opts.format - What style of offset to return. Accepts 'long' or 'short'.
45804
+ * @param {string} opts.locale - What locale to return the offset name in.
45805
+ * @return {string}
45806
+ */
45754
45807
 
45755
- return padded;
45756
- }
45757
- function parseInteger(string) {
45758
- if (isUndefined(string) || string === null || string === "") {
45759
- return undefined;
45760
- } else {
45761
- return parseInt(string, 10);
45762
- }
45763
- }
45764
- function parseFloating(string) {
45765
- if (isUndefined(string) || string === null || string === "") {
45766
- return undefined;
45767
- } else {
45768
- return parseFloat(string);
45769
- }
45770
- }
45771
- function parseMillis(fraction) {
45772
- // Return undefined (instead of 0) in these cases, where fraction is not set
45773
- if (isUndefined(fraction) || fraction === null || fraction === "") {
45774
- return undefined;
45775
- } else {
45776
- const f = parseFloat("0." + fraction) * 1000;
45777
- return Math.floor(f);
45808
+
45809
+ offsetName(ts, opts) {
45810
+ throw new ZoneIsAbstractError();
45778
45811
  }
45779
- }
45780
- function roundTo(number, digits, towardZero = false) {
45781
- const factor = 10 ** digits,
45782
- rounder = towardZero ? Math.trunc : Math.round;
45783
- return rounder(number * factor) / factor;
45784
- } // DATE BASICS
45812
+ /**
45813
+ * Returns the offset's value as a string
45814
+ * @abstract
45815
+ * @param {number} ts - Epoch milliseconds for which to get the offset
45816
+ * @param {string} format - What style of offset to return.
45817
+ * Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively
45818
+ * @return {string}
45819
+ */
45785
45820
 
45786
- function isLeapYear(year) {
45787
- return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
45788
- }
45789
- function daysInYear(year) {
45790
- return isLeapYear(year) ? 366 : 365;
45791
- }
45792
- function daysInMonth(year, month) {
45793
- const modMonth = floorMod(month - 1, 12) + 1,
45794
- modYear = year + (month - modMonth) / 12;
45795
45821
 
45796
- if (modMonth === 2) {
45797
- return isLeapYear(modYear) ? 29 : 28;
45798
- } else {
45799
- return [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][modMonth - 1];
45822
+ formatOffset(ts, format) {
45823
+ throw new ZoneIsAbstractError();
45800
45824
  }
45801
- } // covert a calendar object to a local timestamp (epoch, but with the offset baked in)
45825
+ /**
45826
+ * Return the offset in minutes for this zone at the specified timestamp.
45827
+ * @abstract
45828
+ * @param {number} ts - Epoch milliseconds for which to compute the offset
45829
+ * @return {number}
45830
+ */
45802
45831
 
45803
- function objToLocalTS(obj) {
45804
- let d = Date.UTC(obj.year, obj.month - 1, obj.day, obj.hour, obj.minute, obj.second, obj.millisecond); // for legacy reasons, years between 0 and 99 are interpreted as 19XX; revert that
45805
45832
 
45806
- if (obj.year < 100 && obj.year >= 0) {
45807
- d = new Date(d);
45808
- d.setUTCFullYear(d.getUTCFullYear() - 1900);
45833
+ offset(ts) {
45834
+ throw new ZoneIsAbstractError();
45809
45835
  }
45836
+ /**
45837
+ * Return whether this Zone is equal to another zone
45838
+ * @abstract
45839
+ * @param {Zone} otherZone - the zone to compare
45840
+ * @return {boolean}
45841
+ */
45810
45842
 
45811
- return +d;
45812
- }
45813
- function weeksInWeekYear(weekYear) {
45814
- const p1 = (weekYear + Math.floor(weekYear / 4) - Math.floor(weekYear / 100) + Math.floor(weekYear / 400)) % 7,
45815
- last = weekYear - 1,
45816
- p2 = (last + Math.floor(last / 4) - Math.floor(last / 100) + Math.floor(last / 400)) % 7;
45817
- return p1 === 4 || p2 === 3 ? 53 : 52;
45818
- }
45819
- function untruncateYear(year) {
45820
- if (year > 99) {
45821
- return year;
45822
- } else return year > 60 ? 1900 + year : 2000 + year;
45823
- } // PARSING
45824
-
45825
- function parseZoneInfo(ts, offsetFormat, locale, timeZone = null) {
45826
- const date = new Date(ts),
45827
- intlOpts = {
45828
- hourCycle: "h23",
45829
- year: "numeric",
45830
- month: "2-digit",
45831
- day: "2-digit",
45832
- hour: "2-digit",
45833
- minute: "2-digit"
45834
- };
45835
45843
 
45836
- if (timeZone) {
45837
- intlOpts.timeZone = timeZone;
45844
+ equals(otherZone) {
45845
+ throw new ZoneIsAbstractError();
45838
45846
  }
45847
+ /**
45848
+ * Return whether this Zone is valid.
45849
+ * @abstract
45850
+ * @type {boolean}
45851
+ */
45839
45852
 
45840
- const modified = {
45841
- timeZoneName: offsetFormat,
45842
- ...intlOpts
45843
- };
45844
- const parsed = new Intl.DateTimeFormat(locale, modified).formatToParts(date).find(m => m.type.toLowerCase() === "timezonename");
45845
- return parsed ? parsed.value : null;
45846
- } // signedOffset('-5', '30') -> -330
45847
-
45848
- function signedOffset(offHourStr, offMinuteStr) {
45849
- let offHour = parseInt(offHourStr, 10); // don't || this because we want to preserve -0
45850
45853
 
45851
- if (Number.isNaN(offHour)) {
45852
- offHour = 0;
45854
+ get isValid() {
45855
+ throw new ZoneIsAbstractError();
45853
45856
  }
45854
45857
 
45855
- const offMin = parseInt(offMinuteStr, 10) || 0,
45856
- offMinSigned = offHour < 0 || Object.is(offHour, -0) ? -offMin : offMin;
45857
- return offHour * 60 + offMinSigned;
45858
- } // COERCION
45859
-
45860
- function asNumber(value) {
45861
- const numericValue = Number(value);
45862
- if (typeof value === "boolean" || value === "" || Number.isNaN(numericValue)) throw new InvalidArgumentError(`Invalid unit value ${value}`);
45863
- return numericValue;
45864
45858
  }
45865
- function normalizeObject(obj, normalizer) {
45866
- const normalized = {};
45867
45859
 
45868
- for (const u in obj) {
45869
- if (hasOwnProperty(obj, u)) {
45870
- const v = obj[u];
45871
- if (v === undefined || v === null) continue;
45872
- normalized[normalizer(u)] = asNumber(v);
45860
+ let singleton$1 = null;
45861
+ /**
45862
+ * Represents the local zone for this JavaScript environment.
45863
+ * @implements {Zone}
45864
+ */
45865
+
45866
+ class SystemZone extends Zone {
45867
+ /**
45868
+ * Get a singleton instance of the local zone
45869
+ * @return {SystemZone}
45870
+ */
45871
+ static get instance() {
45872
+ if (singleton$1 === null) {
45873
+ singleton$1 = new SystemZone();
45873
45874
  }
45874
- }
45875
45875
 
45876
- return normalized;
45877
- }
45878
- function formatOffset(offset, format) {
45879
- const hours = Math.trunc(Math.abs(offset / 60)),
45880
- minutes = Math.trunc(Math.abs(offset % 60)),
45881
- sign = offset >= 0 ? "+" : "-";
45876
+ return singleton$1;
45877
+ }
45878
+ /** @override **/
45882
45879
 
45883
- switch (format) {
45884
- case "short":
45885
- return `${sign}${padStart(hours, 2)}:${padStart(minutes, 2)}`;
45886
45880
 
45887
- case "narrow":
45888
- return `${sign}${hours}${minutes > 0 ? `:${minutes}` : ""}`;
45881
+ get type() {
45882
+ return "system";
45883
+ }
45884
+ /** @override **/
45889
45885
 
45890
- case "techie":
45891
- return `${sign}${padStart(hours, 2)}${padStart(minutes, 2)}`;
45892
45886
 
45893
- default:
45894
- throw new RangeError(`Value format ${format} is out of range for property format`);
45887
+ get name() {
45888
+ return new Intl.DateTimeFormat().resolvedOptions().timeZone;
45895
45889
  }
45896
- }
45897
- function timeObject(obj) {
45898
- return pick(obj, ["hour", "minute", "second", "millisecond"]);
45899
- }
45900
- const ianaRegex = /[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;
45890
+ /** @override **/
45901
45891
 
45902
- /**
45903
- * @private
45904
- */
45905
45892
 
45893
+ get isUniversal() {
45894
+ return false;
45895
+ }
45896
+ /** @override **/
45906
45897
 
45907
- const monthsLong = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
45908
- const monthsShort = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
45909
- const monthsNarrow = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"];
45910
- function months(length) {
45911
- switch (length) {
45912
- case "narrow":
45913
- return [...monthsNarrow];
45914
45898
 
45915
- case "short":
45916
- return [...monthsShort];
45899
+ offsetName(ts, {
45900
+ format,
45901
+ locale
45902
+ }) {
45903
+ return parseZoneInfo(ts, format, locale);
45904
+ }
45905
+ /** @override **/
45917
45906
 
45918
- case "long":
45919
- return [...monthsLong];
45920
45907
 
45921
- case "numeric":
45922
- return ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
45908
+ formatOffset(ts, format) {
45909
+ return formatOffset(this.offset(ts), format);
45910
+ }
45911
+ /** @override **/
45923
45912
 
45924
- case "2-digit":
45925
- return ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"];
45926
45913
 
45927
- default:
45928
- return null;
45914
+ offset(ts) {
45915
+ return -new Date(ts).getTimezoneOffset();
45929
45916
  }
45930
- }
45931
- const weekdaysLong = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
45932
- const weekdaysShort = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
45933
- const weekdaysNarrow = ["M", "T", "W", "T", "F", "S", "S"];
45934
- function weekdays(length) {
45935
- switch (length) {
45936
- case "narrow":
45937
- return [...weekdaysNarrow];
45917
+ /** @override **/
45938
45918
 
45939
- case "short":
45940
- return [...weekdaysShort];
45941
45919
 
45942
- case "long":
45943
- return [...weekdaysLong];
45920
+ equals(otherZone) {
45921
+ return otherZone.type === "system";
45922
+ }
45923
+ /** @override **/
45944
45924
 
45945
- case "numeric":
45946
- return ["1", "2", "3", "4", "5", "6", "7"];
45947
45925
 
45948
- default:
45949
- return null;
45926
+ get isValid() {
45927
+ return true;
45950
45928
  }
45951
- }
45952
- const meridiems = ["AM", "PM"];
45953
- const erasLong = ["Before Christ", "Anno Domini"];
45954
- const erasShort = ["BC", "AD"];
45955
- const erasNarrow = ["B", "A"];
45956
- function eras(length) {
45957
- switch (length) {
45958
- case "narrow":
45959
- return [...erasNarrow];
45960
45929
 
45961
- case "short":
45962
- return [...erasShort];
45930
+ }
45963
45931
 
45964
- case "long":
45965
- return [...erasLong];
45932
+ let dtfCache = {};
45966
45933
 
45967
- default:
45968
- return null;
45934
+ function makeDTF(zone) {
45935
+ if (!dtfCache[zone]) {
45936
+ dtfCache[zone] = new Intl.DateTimeFormat("en-US", {
45937
+ hour12: false,
45938
+ timeZone: zone,
45939
+ year: "numeric",
45940
+ month: "2-digit",
45941
+ day: "2-digit",
45942
+ hour: "2-digit",
45943
+ minute: "2-digit",
45944
+ second: "2-digit",
45945
+ era: "short"
45946
+ });
45969
45947
  }
45948
+
45949
+ return dtfCache[zone];
45970
45950
  }
45971
- function meridiemForDateTime(dt) {
45972
- return meridiems[dt.hour < 12 ? 0 : 1];
45973
- }
45974
- function weekdayForDateTime(dt, length) {
45975
- return weekdays(length)[dt.weekday - 1];
45976
- }
45977
- function monthForDateTime(dt, length) {
45978
- return months(length)[dt.month - 1];
45979
- }
45980
- function eraForDateTime(dt, length) {
45981
- return eras(length)[dt.year < 0 ? 0 : 1];
45982
- }
45983
- function formatRelativeTime(unit, count, numeric = "always", narrow = false) {
45984
- const units = {
45985
- years: ["year", "yr."],
45986
- quarters: ["quarter", "qtr."],
45987
- months: ["month", "mo."],
45988
- weeks: ["week", "wk."],
45989
- days: ["day", "day", "days"],
45990
- hours: ["hour", "hr."],
45991
- minutes: ["minute", "min."],
45992
- seconds: ["second", "sec."]
45993
- };
45994
- const lastable = ["hours", "minutes", "seconds"].indexOf(unit) === -1;
45995
45951
 
45996
- if (numeric === "auto" && lastable) {
45997
- const isDay = unit === "days";
45952
+ const typeToPos = {
45953
+ year: 0,
45954
+ month: 1,
45955
+ day: 2,
45956
+ era: 3,
45957
+ hour: 4,
45958
+ minute: 5,
45959
+ second: 6
45960
+ };
45998
45961
 
45999
- switch (count) {
46000
- case 1:
46001
- return isDay ? "tomorrow" : `next ${units[unit][0]}`;
45962
+ function hackyOffset(dtf, date) {
45963
+ const formatted = dtf.format(date).replace(/\u200E/g, ""),
45964
+ parsed = /(\d+)\/(\d+)\/(\d+) (AD|BC),? (\d+):(\d+):(\d+)/.exec(formatted),
45965
+ [, fMonth, fDay, fYear, fadOrBc, fHour, fMinute, fSecond] = parsed;
45966
+ return [fYear, fMonth, fDay, fadOrBc, fHour, fMinute, fSecond];
45967
+ }
46002
45968
 
46003
- case -1:
46004
- return isDay ? "yesterday" : `last ${units[unit][0]}`;
45969
+ function partsOffset(dtf, date) {
45970
+ const formatted = dtf.formatToParts(date);
45971
+ const filled = [];
46005
45972
 
46006
- case 0:
46007
- return isDay ? "today" : `this ${units[unit][0]}`;
45973
+ for (let i = 0; i < formatted.length; i++) {
45974
+ const {
45975
+ type,
45976
+ value
45977
+ } = formatted[i];
45978
+ const pos = typeToPos[type];
46008
45979
 
45980
+ if (type === "era") {
45981
+ filled[pos] = value;
45982
+ } else if (!isUndefined(pos)) {
45983
+ filled[pos] = parseInt(value, 10);
46009
45984
  }
46010
45985
  }
46011
45986
 
46012
- const isInPast = Object.is(count, -0) || count < 0,
46013
- fmtValue = Math.abs(count),
46014
- singular = fmtValue === 1,
46015
- lilUnits = units[unit],
46016
- fmtUnit = narrow ? singular ? lilUnits[1] : lilUnits[2] || lilUnits[1] : singular ? units[unit][0] : unit;
46017
- return isInPast ? `${fmtValue} ${fmtUnit} ago` : `in ${fmtValue} ${fmtUnit}`;
45987
+ return filled;
46018
45988
  }
46019
45989
 
46020
- function stringifyTokens(splits, tokenToString) {
46021
- let s = "";
45990
+ let ianaZoneCache = {};
45991
+ /**
45992
+ * A zone identified by an IANA identifier, like America/New_York
45993
+ * @implements {Zone}
45994
+ */
46022
45995
 
46023
- for (const token of splits) {
46024
- if (token.literal) {
46025
- s += token.val;
46026
- } else {
46027
- s += tokenToString(token.val);
45996
+ class IANAZone extends Zone {
45997
+ /**
45998
+ * @param {string} name - Zone name
45999
+ * @return {IANAZone}
46000
+ */
46001
+ static create(name) {
46002
+ if (!ianaZoneCache[name]) {
46003
+ ianaZoneCache[name] = new IANAZone(name);
46028
46004
  }
46029
- }
46030
46005
 
46031
- return s;
46032
- }
46006
+ return ianaZoneCache[name];
46007
+ }
46008
+ /**
46009
+ * Reset local caches. Should only be necessary in testing scenarios.
46010
+ * @return {void}
46011
+ */
46033
46012
 
46034
- const macroTokenToFormatOpts = {
46035
- D: DATE_SHORT,
46036
- DD: DATE_MED,
46037
- DDD: DATE_FULL,
46038
- DDDD: DATE_HUGE,
46039
- t: TIME_SIMPLE,
46040
- tt: TIME_WITH_SECONDS,
46041
- ttt: TIME_WITH_SHORT_OFFSET,
46042
- tttt: TIME_WITH_LONG_OFFSET,
46043
- T: TIME_24_SIMPLE,
46044
- TT: TIME_24_WITH_SECONDS,
46045
- TTT: TIME_24_WITH_SHORT_OFFSET,
46046
- TTTT: TIME_24_WITH_LONG_OFFSET,
46047
- f: DATETIME_SHORT,
46048
- ff: DATETIME_MED,
46049
- fff: DATETIME_FULL,
46050
- ffff: DATETIME_HUGE,
46051
- F: DATETIME_SHORT_WITH_SECONDS,
46052
- FF: DATETIME_MED_WITH_SECONDS,
46053
- FFF: DATETIME_FULL_WITH_SECONDS,
46054
- FFFF: DATETIME_HUGE_WITH_SECONDS
46055
- };
46056
- /**
46057
- * @private
46058
- */
46059
46013
 
46060
- class Formatter {
46061
- static create(locale, opts = {}) {
46062
- return new Formatter(locale, opts);
46014
+ static resetCache() {
46015
+ ianaZoneCache = {};
46016
+ dtfCache = {};
46063
46017
  }
46018
+ /**
46019
+ * Returns whether the provided string is a valid specifier. This only checks the string's format, not that the specifier identifies a known zone; see isValidZone for that.
46020
+ * @param {string} s - The string to check validity on
46021
+ * @example IANAZone.isValidSpecifier("America/New_York") //=> true
46022
+ * @example IANAZone.isValidSpecifier("Sport~~blorp") //=> false
46023
+ * @deprecated This method returns false for some valid IANA names. Use isValidZone instead.
46024
+ * @return {boolean}
46025
+ */
46064
46026
 
46065
- static parseFormat(fmt) {
46066
- let current = null,
46067
- currentFull = "",
46068
- bracketed = false;
46069
- const splits = [];
46070
-
46071
- for (let i = 0; i < fmt.length; i++) {
46072
- const c = fmt.charAt(i);
46073
46027
 
46074
- if (c === "'") {
46075
- if (currentFull.length > 0) {
46076
- splits.push({
46077
- literal: bracketed,
46078
- val: currentFull
46079
- });
46080
- }
46028
+ static isValidSpecifier(s) {
46029
+ return this.isValidZone(s);
46030
+ }
46031
+ /**
46032
+ * Returns whether the provided string identifies a real zone
46033
+ * @param {string} zone - The string to check
46034
+ * @example IANAZone.isValidZone("America/New_York") //=> true
46035
+ * @example IANAZone.isValidZone("Fantasia/Castle") //=> false
46036
+ * @example IANAZone.isValidZone("Sport~~blorp") //=> false
46037
+ * @return {boolean}
46038
+ */
46081
46039
 
46082
- current = null;
46083
- currentFull = "";
46084
- bracketed = !bracketed;
46085
- } else if (bracketed) {
46086
- currentFull += c;
46087
- } else if (c === current) {
46088
- currentFull += c;
46089
- } else {
46090
- if (currentFull.length > 0) {
46091
- splits.push({
46092
- literal: false,
46093
- val: currentFull
46094
- });
46095
- }
46096
46040
 
46097
- currentFull = c;
46098
- current = c;
46099
- }
46041
+ static isValidZone(zone) {
46042
+ if (!zone) {
46043
+ return false;
46100
46044
  }
46101
46045
 
46102
- if (currentFull.length > 0) {
46103
- splits.push({
46104
- literal: bracketed,
46105
- val: currentFull
46106
- });
46046
+ try {
46047
+ new Intl.DateTimeFormat("en-US", {
46048
+ timeZone: zone
46049
+ }).format();
46050
+ return true;
46051
+ } catch (e) {
46052
+ return false;
46107
46053
  }
46108
-
46109
- return splits;
46110
46054
  }
46111
46055
 
46112
- static macroTokenToFormatOpts(token) {
46113
- return macroTokenToFormatOpts[token];
46114
- }
46056
+ constructor(name) {
46057
+ super();
46058
+ /** @private **/
46115
46059
 
46116
- constructor(locale, formatOpts) {
46117
- this.opts = formatOpts;
46118
- this.loc = locale;
46119
- this.systemLoc = null;
46060
+ this.zoneName = name;
46061
+ /** @private **/
46062
+
46063
+ this.valid = IANAZone.isValidZone(name);
46120
46064
  }
46065
+ /** @override **/
46121
46066
 
46122
- formatWithSystemDefault(dt, opts) {
46123
- if (this.systemLoc === null) {
46124
- this.systemLoc = this.loc.redefaultToSystem();
46125
- }
46126
46067
 
46127
- const df = this.systemLoc.dtFormatter(dt, { ...this.opts,
46128
- ...opts
46129
- });
46130
- return df.format();
46068
+ get type() {
46069
+ return "iana";
46131
46070
  }
46071
+ /** @override **/
46132
46072
 
46133
- formatDateTime(dt, opts = {}) {
46134
- const df = this.loc.dtFormatter(dt, { ...this.opts,
46135
- ...opts
46136
- });
46137
- return df.format();
46138
- }
46139
46073
 
46140
- formatDateTimeParts(dt, opts = {}) {
46141
- const df = this.loc.dtFormatter(dt, { ...this.opts,
46142
- ...opts
46143
- });
46144
- return df.formatToParts();
46074
+ get name() {
46075
+ return this.zoneName;
46145
46076
  }
46077
+ /** @override **/
46146
46078
 
46147
- resolvedOptions(dt, opts = {}) {
46148
- const df = this.loc.dtFormatter(dt, { ...this.opts,
46149
- ...opts
46150
- });
46151
- return df.resolvedOptions();
46079
+
46080
+ get isUniversal() {
46081
+ return false;
46152
46082
  }
46083
+ /** @override **/
46153
46084
 
46154
- num(n, p = 0) {
46155
- // we get some perf out of doing this here, annoyingly
46156
- if (this.opts.forceSimple) {
46157
- return padStart(n, p);
46158
- }
46159
46085
 
46160
- const opts = { ...this.opts
46161
- };
46086
+ offsetName(ts, {
46087
+ format,
46088
+ locale
46089
+ }) {
46090
+ return parseZoneInfo(ts, format, locale, this.name);
46091
+ }
46092
+ /** @override **/
46162
46093
 
46163
- if (p > 0) {
46164
- opts.padTo = p;
46165
- }
46166
46094
 
46167
- return this.loc.numberFormatter(opts).format(n);
46095
+ formatOffset(ts, format) {
46096
+ return formatOffset(this.offset(ts), format);
46168
46097
  }
46098
+ /** @override **/
46169
46099
 
46170
- formatDateTimeFromString(dt, fmt) {
46171
- const knownEnglish = this.loc.listingMode() === "en",
46172
- useDateTimeFormatter = this.loc.outputCalendar && this.loc.outputCalendar !== "gregory",
46173
- string = (opts, extract) => this.loc.extract(dt, opts, extract),
46174
- formatOffset = opts => {
46175
- if (dt.isOffsetFixed && dt.offset === 0 && opts.allowZ) {
46176
- return "Z";
46177
- }
46178
-
46179
- return dt.isValid ? dt.zone.formatOffset(dt.ts, opts.format) : "";
46180
- },
46181
- meridiem = () => knownEnglish ? meridiemForDateTime(dt) : string({
46182
- hour: "numeric",
46183
- hourCycle: "h12"
46184
- }, "dayperiod"),
46185
- month = (length, standalone) => knownEnglish ? monthForDateTime(dt, length) : string(standalone ? {
46186
- month: length
46187
- } : {
46188
- month: length,
46189
- day: "numeric"
46190
- }, "month"),
46191
- weekday = (length, standalone) => knownEnglish ? weekdayForDateTime(dt, length) : string(standalone ? {
46192
- weekday: length
46193
- } : {
46194
- weekday: length,
46195
- month: "long",
46196
- day: "numeric"
46197
- }, "weekday"),
46198
- maybeMacro = token => {
46199
- const formatOpts = Formatter.macroTokenToFormatOpts(token);
46200
46100
 
46201
- if (formatOpts) {
46202
- return this.formatWithSystemDefault(dt, formatOpts);
46203
- } else {
46204
- return token;
46205
- }
46206
- },
46207
- era = length => knownEnglish ? eraForDateTime(dt, length) : string({
46208
- era: length
46209
- }, "era"),
46210
- tokenToString = token => {
46211
- // Where possible: http://cldr.unicode.org/translation/date-time-1/date-time#TOC-Standalone-vs.-Format-Styles
46212
- switch (token) {
46213
- // ms
46214
- case "S":
46215
- return this.num(dt.millisecond);
46101
+ offset(ts) {
46102
+ const date = new Date(ts);
46103
+ if (isNaN(date)) return NaN;
46104
+ const dtf = makeDTF(this.name);
46105
+ let [year, month, day, adOrBc, hour, minute, second] = dtf.formatToParts ? partsOffset(dtf, date) : hackyOffset(dtf, date);
46216
46106
 
46217
- case "u": // falls through
46107
+ if (adOrBc === "BC") {
46108
+ year = -Math.abs(year) + 1;
46109
+ } // because we're using hour12 and https://bugs.chromium.org/p/chromium/issues/detail?id=1025564&can=2&q=%2224%3A00%22%20datetimeformat
46218
46110
 
46219
- case "SSS":
46220
- return this.num(dt.millisecond, 3);
46221
- // seconds
46222
46111
 
46223
- case "s":
46224
- return this.num(dt.second);
46112
+ const adjustedHour = hour === 24 ? 0 : hour;
46113
+ const asUTC = objToLocalTS({
46114
+ year,
46115
+ month,
46116
+ day,
46117
+ hour: adjustedHour,
46118
+ minute,
46119
+ second,
46120
+ millisecond: 0
46121
+ });
46122
+ let asTS = +date;
46123
+ const over = asTS % 1000;
46124
+ asTS -= over >= 0 ? over : 1000 + over;
46125
+ return (asUTC - asTS) / (60 * 1000);
46126
+ }
46127
+ /** @override **/
46225
46128
 
46226
- case "ss":
46227
- return this.num(dt.second, 2);
46228
- // fractional seconds
46229
46129
 
46230
- case "uu":
46231
- return this.num(Math.floor(dt.millisecond / 10), 2);
46130
+ equals(otherZone) {
46131
+ return otherZone.type === "iana" && otherZone.name === this.name;
46132
+ }
46133
+ /** @override **/
46232
46134
 
46233
- case "uuu":
46234
- return this.num(Math.floor(dt.millisecond / 100));
46235
- // minutes
46236
46135
 
46237
- case "m":
46238
- return this.num(dt.minute);
46136
+ get isValid() {
46137
+ return this.valid;
46138
+ }
46239
46139
 
46240
- case "mm":
46241
- return this.num(dt.minute, 2);
46242
- // hours
46140
+ }
46243
46141
 
46244
- case "h":
46245
- return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12);
46142
+ let intlLFCache = {};
46246
46143
 
46247
- case "hh":
46248
- return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12, 2);
46144
+ function getCachedLF(locString, opts = {}) {
46145
+ const key = JSON.stringify([locString, opts]);
46146
+ let dtf = intlLFCache[key];
46249
46147
 
46250
- case "H":
46251
- return this.num(dt.hour);
46148
+ if (!dtf) {
46149
+ dtf = new Intl.ListFormat(locString, opts);
46150
+ intlLFCache[key] = dtf;
46151
+ }
46252
46152
 
46253
- case "HH":
46254
- return this.num(dt.hour, 2);
46255
- // offset
46153
+ return dtf;
46154
+ }
46256
46155
 
46257
- case "Z":
46258
- // like +6
46259
- return formatOffset({
46260
- format: "narrow",
46261
- allowZ: this.opts.allowZ
46262
- });
46156
+ let intlDTCache = {};
46263
46157
 
46264
- case "ZZ":
46265
- // like +06:00
46266
- return formatOffset({
46267
- format: "short",
46268
- allowZ: this.opts.allowZ
46269
- });
46158
+ function getCachedDTF(locString, opts = {}) {
46159
+ const key = JSON.stringify([locString, opts]);
46160
+ let dtf = intlDTCache[key];
46270
46161
 
46271
- case "ZZZ":
46272
- // like +0600
46273
- return formatOffset({
46274
- format: "techie",
46275
- allowZ: this.opts.allowZ
46276
- });
46162
+ if (!dtf) {
46163
+ dtf = new Intl.DateTimeFormat(locString, opts);
46164
+ intlDTCache[key] = dtf;
46165
+ }
46277
46166
 
46278
- case "ZZZZ":
46279
- // like EST
46280
- return dt.zone.offsetName(dt.ts, {
46281
- format: "short",
46282
- locale: this.loc.locale
46283
- });
46167
+ return dtf;
46168
+ }
46284
46169
 
46285
- case "ZZZZZ":
46286
- // like Eastern Standard Time
46287
- return dt.zone.offsetName(dt.ts, {
46288
- format: "long",
46289
- locale: this.loc.locale
46290
- });
46291
- // zone
46170
+ let intlNumCache = {};
46292
46171
 
46293
- case "z":
46294
- // like America/New_York
46295
- return dt.zoneName;
46296
- // meridiems
46172
+ function getCachedINF(locString, opts = {}) {
46173
+ const key = JSON.stringify([locString, opts]);
46174
+ let inf = intlNumCache[key];
46297
46175
 
46298
- case "a":
46299
- return meridiem();
46300
- // dates
46176
+ if (!inf) {
46177
+ inf = new Intl.NumberFormat(locString, opts);
46178
+ intlNumCache[key] = inf;
46179
+ }
46301
46180
 
46302
- case "d":
46303
- return useDateTimeFormatter ? string({
46304
- day: "numeric"
46305
- }, "day") : this.num(dt.day);
46181
+ return inf;
46182
+ }
46306
46183
 
46307
- case "dd":
46308
- return useDateTimeFormatter ? string({
46309
- day: "2-digit"
46310
- }, "day") : this.num(dt.day, 2);
46311
- // weekdays - standalone
46184
+ let intlRelCache = {};
46312
46185
 
46313
- case "c":
46314
- // like 1
46315
- return this.num(dt.weekday);
46186
+ function getCachedRTF(locString, opts = {}) {
46187
+ const {
46188
+ base,
46189
+ ...cacheKeyOpts
46190
+ } = opts; // exclude `base` from the options
46316
46191
 
46317
- case "ccc":
46318
- // like 'Tues'
46319
- return weekday("short", true);
46192
+ const key = JSON.stringify([locString, cacheKeyOpts]);
46193
+ let inf = intlRelCache[key];
46320
46194
 
46321
- case "cccc":
46322
- // like 'Tuesday'
46323
- return weekday("long", true);
46195
+ if (!inf) {
46196
+ inf = new Intl.RelativeTimeFormat(locString, opts);
46197
+ intlRelCache[key] = inf;
46198
+ }
46324
46199
 
46325
- case "ccccc":
46326
- // like 'T'
46327
- return weekday("narrow", true);
46328
- // weekdays - format
46200
+ return inf;
46201
+ }
46329
46202
 
46330
- case "E":
46331
- // like 1
46332
- return this.num(dt.weekday);
46203
+ let sysLocaleCache = null;
46333
46204
 
46334
- case "EEE":
46335
- // like 'Tues'
46336
- return weekday("short", false);
46205
+ function systemLocale() {
46206
+ if (sysLocaleCache) {
46207
+ return sysLocaleCache;
46208
+ } else {
46209
+ sysLocaleCache = new Intl.DateTimeFormat().resolvedOptions().locale;
46210
+ return sysLocaleCache;
46211
+ }
46212
+ }
46337
46213
 
46338
- case "EEEE":
46339
- // like 'Tuesday'
46340
- return weekday("long", false);
46214
+ function parseLocaleString(localeStr) {
46215
+ // I really want to avoid writing a BCP 47 parser
46216
+ // see, e.g. https://github.com/wooorm/bcp-47
46217
+ // Instead, we'll do this:
46218
+ // a) if the string has no -u extensions, just leave it alone
46219
+ // b) if it does, use Intl to resolve everything
46220
+ // c) if Intl fails, try again without the -u
46221
+ const uIndex = localeStr.indexOf("-u-");
46341
46222
 
46342
- case "EEEEE":
46343
- // like 'T'
46344
- return weekday("narrow", false);
46345
- // months - standalone
46223
+ if (uIndex === -1) {
46224
+ return [localeStr];
46225
+ } else {
46226
+ let options;
46227
+ const smaller = localeStr.substring(0, uIndex);
46346
46228
 
46347
- case "L":
46348
- // like 1
46349
- return useDateTimeFormatter ? string({
46350
- month: "numeric",
46351
- day: "numeric"
46352
- }, "month") : this.num(dt.month);
46229
+ try {
46230
+ options = getCachedDTF(localeStr).resolvedOptions();
46231
+ } catch (e) {
46232
+ options = getCachedDTF(smaller).resolvedOptions();
46233
+ }
46353
46234
 
46354
- case "LL":
46355
- // like 01, doesn't seem to work
46356
- return useDateTimeFormatter ? string({
46357
- month: "2-digit",
46358
- day: "numeric"
46359
- }, "month") : this.num(dt.month, 2);
46235
+ const {
46236
+ numberingSystem,
46237
+ calendar
46238
+ } = options; // return the smaller one so that we can append the calendar and numbering overrides to it
46360
46239
 
46361
- case "LLL":
46362
- // like Jan
46363
- return month("short", true);
46240
+ return [smaller, numberingSystem, calendar];
46241
+ }
46242
+ }
46364
46243
 
46365
- case "LLLL":
46366
- // like January
46367
- return month("long", true);
46244
+ function intlConfigString(localeStr, numberingSystem, outputCalendar) {
46245
+ if (outputCalendar || numberingSystem) {
46246
+ localeStr += "-u";
46368
46247
 
46369
- case "LLLLL":
46370
- // like J
46371
- return month("narrow", true);
46372
- // months - format
46248
+ if (outputCalendar) {
46249
+ localeStr += `-ca-${outputCalendar}`;
46250
+ }
46373
46251
 
46374
- case "M":
46375
- // like 1
46376
- return useDateTimeFormatter ? string({
46377
- month: "numeric"
46378
- }, "month") : this.num(dt.month);
46252
+ if (numberingSystem) {
46253
+ localeStr += `-nu-${numberingSystem}`;
46254
+ }
46379
46255
 
46380
- case "MM":
46381
- // like 01
46382
- return useDateTimeFormatter ? string({
46383
- month: "2-digit"
46384
- }, "month") : this.num(dt.month, 2);
46256
+ return localeStr;
46257
+ } else {
46258
+ return localeStr;
46259
+ }
46260
+ }
46385
46261
 
46386
- case "MMM":
46387
- // like Jan
46388
- return month("short", false);
46262
+ function mapMonths(f) {
46263
+ const ms = [];
46389
46264
 
46390
- case "MMMM":
46391
- // like January
46392
- return month("long", false);
46265
+ for (let i = 1; i <= 12; i++) {
46266
+ const dt = DateTime.utc(2016, i, 1);
46267
+ ms.push(f(dt));
46268
+ }
46393
46269
 
46394
- case "MMMMM":
46395
- // like J
46396
- return month("narrow", false);
46397
- // years
46398
-
46399
- case "y":
46400
- // like 2014
46401
- return useDateTimeFormatter ? string({
46402
- year: "numeric"
46403
- }, "year") : this.num(dt.year);
46404
-
46405
- case "yy":
46406
- // like 14
46407
- return useDateTimeFormatter ? string({
46408
- year: "2-digit"
46409
- }, "year") : this.num(dt.year.toString().slice(-2), 2);
46270
+ return ms;
46271
+ }
46410
46272
 
46411
- case "yyyy":
46412
- // like 0012
46413
- return useDateTimeFormatter ? string({
46414
- year: "numeric"
46415
- }, "year") : this.num(dt.year, 4);
46273
+ function mapWeekdays(f) {
46274
+ const ms = [];
46416
46275
 
46417
- case "yyyyyy":
46418
- // like 000012
46419
- return useDateTimeFormatter ? string({
46420
- year: "numeric"
46421
- }, "year") : this.num(dt.year, 6);
46422
- // eras
46276
+ for (let i = 1; i <= 7; i++) {
46277
+ const dt = DateTime.utc(2016, 11, 13 + i);
46278
+ ms.push(f(dt));
46279
+ }
46423
46280
 
46424
- case "G":
46425
- // like AD
46426
- return era("short");
46281
+ return ms;
46282
+ }
46427
46283
 
46428
- case "GG":
46429
- // like Anno Domini
46430
- return era("long");
46284
+ function listStuff(loc, length, defaultOK, englishFn, intlFn) {
46285
+ const mode = loc.listingMode(defaultOK);
46431
46286
 
46432
- case "GGGGG":
46433
- return era("narrow");
46287
+ if (mode === "error") {
46288
+ return null;
46289
+ } else if (mode === "en") {
46290
+ return englishFn(length);
46291
+ } else {
46292
+ return intlFn(length);
46293
+ }
46294
+ }
46434
46295
 
46435
- case "kk":
46436
- return this.num(dt.weekYear.toString().slice(-2), 2);
46296
+ function supportsFastNumbers(loc) {
46297
+ if (loc.numberingSystem && loc.numberingSystem !== "latn") {
46298
+ return false;
46299
+ } else {
46300
+ return loc.numberingSystem === "latn" || !loc.locale || loc.locale.startsWith("en") || new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem === "latn";
46301
+ }
46302
+ }
46303
+ /**
46304
+ * @private
46305
+ */
46437
46306
 
46438
- case "kkkk":
46439
- return this.num(dt.weekYear, 4);
46440
46307
 
46441
- case "W":
46442
- return this.num(dt.weekNumber);
46308
+ class PolyNumberFormatter {
46309
+ constructor(intl, forceSimple, opts) {
46310
+ this.padTo = opts.padTo || 0;
46311
+ this.floor = opts.floor || false;
46312
+ const {
46313
+ padTo,
46314
+ floor,
46315
+ ...otherOpts
46316
+ } = opts;
46443
46317
 
46444
- case "WW":
46445
- return this.num(dt.weekNumber, 2);
46318
+ if (!forceSimple || Object.keys(otherOpts).length > 0) {
46319
+ const intlOpts = {
46320
+ useGrouping: false,
46321
+ ...opts
46322
+ };
46323
+ if (opts.padTo > 0) intlOpts.minimumIntegerDigits = opts.padTo;
46324
+ this.inf = getCachedINF(intl, intlOpts);
46325
+ }
46326
+ }
46446
46327
 
46447
- case "o":
46448
- return this.num(dt.ordinal);
46328
+ format(i) {
46329
+ if (this.inf) {
46330
+ const fixed = this.floor ? Math.floor(i) : i;
46331
+ return this.inf.format(fixed);
46332
+ } else {
46333
+ // to match the browser's numberformatter defaults
46334
+ const fixed = this.floor ? Math.floor(i) : roundTo(i, 3);
46335
+ return padStart(fixed, this.padTo);
46336
+ }
46337
+ }
46449
46338
 
46450
- case "ooo":
46451
- return this.num(dt.ordinal, 3);
46339
+ }
46340
+ /**
46341
+ * @private
46342
+ */
46452
46343
 
46453
- case "q":
46454
- // like 1
46455
- return this.num(dt.quarter);
46456
46344
 
46457
- case "qq":
46458
- // like 01
46459
- return this.num(dt.quarter, 2);
46345
+ class PolyDateFormatter {
46346
+ constructor(dt, intl, opts) {
46347
+ this.opts = opts;
46348
+ let z;
46460
46349
 
46461
- case "X":
46462
- return this.num(Math.floor(dt.ts / 1000));
46350
+ if (dt.zone.isUniversal) {
46351
+ // UTC-8 or Etc/UTC-8 are not part of tzdata, only Etc/GMT+8 and the like.
46352
+ // That is why fixed-offset TZ is set to that unless it is:
46353
+ // 1. Representing offset 0 when UTC is used to maintain previous behavior and does not become GMT.
46354
+ // 2. Unsupported by the browser:
46355
+ // - some do not support Etc/
46356
+ // - < Etc/GMT-14, > Etc/GMT+12, and 30-minute or 45-minute offsets are not part of tzdata
46357
+ const gmtOffset = -1 * (dt.offset / 60);
46358
+ const offsetZ = gmtOffset >= 0 ? `Etc/GMT+${gmtOffset}` : `Etc/GMT${gmtOffset}`;
46463
46359
 
46464
- case "x":
46465
- return this.num(dt.ts);
46360
+ if (dt.offset !== 0 && IANAZone.create(offsetZ).valid) {
46361
+ z = offsetZ;
46362
+ this.dt = dt;
46363
+ } else {
46364
+ // Not all fixed-offset zones like Etc/+4:30 are present in tzdata.
46365
+ // So we have to make do. Two cases:
46366
+ // 1. The format options tell us to show the zone. We can't do that, so the best
46367
+ // we can do is format the date in UTC.
46368
+ // 2. The format options don't tell us to show the zone. Then we can adjust them
46369
+ // the time and tell the formatter to show it to us in UTC, so that the time is right
46370
+ // and the bad zone doesn't show up.
46371
+ z = "UTC";
46466
46372
 
46467
- default:
46468
- return maybeMacro(token);
46373
+ if (opts.timeZoneName) {
46374
+ this.dt = dt;
46375
+ } else {
46376
+ this.dt = dt.offset === 0 ? dt : DateTime.fromMillis(dt.ts + dt.offset * 60 * 1000);
46377
+ }
46469
46378
  }
46470
- };
46471
-
46472
- return stringifyTokens(Formatter.parseFormat(fmt), tokenToString);
46473
- }
46474
-
46475
- formatDurationFromString(dur, fmt) {
46476
- const tokenToField = token => {
46477
- switch (token[0]) {
46478
- case "S":
46479
- return "millisecond";
46379
+ } else if (dt.zone.type === "system") {
46380
+ this.dt = dt;
46381
+ } else {
46382
+ this.dt = dt;
46383
+ z = dt.zone.name;
46384
+ }
46480
46385
 
46481
- case "s":
46482
- return "second";
46386
+ const intlOpts = { ...this.opts
46387
+ };
46483
46388
 
46484
- case "m":
46485
- return "minute";
46389
+ if (z) {
46390
+ intlOpts.timeZone = z;
46391
+ }
46486
46392
 
46487
- case "h":
46488
- return "hour";
46393
+ this.dtf = getCachedDTF(intl, intlOpts);
46394
+ }
46489
46395
 
46490
- case "d":
46491
- return "day";
46396
+ format() {
46397
+ return this.dtf.format(this.dt.toJSDate());
46398
+ }
46492
46399
 
46493
- case "w":
46494
- return "week";
46400
+ formatToParts() {
46401
+ return this.dtf.formatToParts(this.dt.toJSDate());
46402
+ }
46495
46403
 
46496
- case "M":
46497
- return "month";
46404
+ resolvedOptions() {
46405
+ return this.dtf.resolvedOptions();
46406
+ }
46498
46407
 
46499
- case "y":
46500
- return "year";
46408
+ }
46409
+ /**
46410
+ * @private
46411
+ */
46501
46412
 
46502
- default:
46503
- return null;
46504
- }
46505
- },
46506
- tokenToString = lildur => token => {
46507
- const mapped = tokenToField(token);
46508
46413
 
46509
- if (mapped) {
46510
- return this.num(lildur.get(mapped), token.length);
46511
- } else {
46512
- return token;
46513
- }
46514
- },
46515
- tokens = Formatter.parseFormat(fmt),
46516
- realTokens = tokens.reduce((found, {
46517
- literal,
46518
- val
46519
- }) => literal ? found : found.concat(val), []),
46520
- collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter(t => t));
46414
+ class PolyRelFormatter {
46415
+ constructor(intl, isEnglish, opts) {
46416
+ this.opts = {
46417
+ style: "long",
46418
+ ...opts
46419
+ };
46521
46420
 
46522
- return stringifyTokens(tokens, tokenToString(collapsed));
46421
+ if (!isEnglish && hasRelative()) {
46422
+ this.rtf = getCachedRTF(intl, opts);
46423
+ }
46523
46424
  }
46524
46425
 
46525
- }
46526
-
46527
- class Invalid {
46528
- constructor(reason, explanation) {
46529
- this.reason = reason;
46530
- this.explanation = explanation;
46426
+ format(count, unit) {
46427
+ if (this.rtf) {
46428
+ return this.rtf.format(count, unit);
46429
+ } else {
46430
+ return formatRelativeTime(unit, count, this.opts.numeric, this.opts.style !== "long");
46431
+ }
46531
46432
  }
46532
46433
 
46533
- toMessage() {
46534
- if (this.explanation) {
46535
- return `${this.reason}: ${this.explanation}`;
46434
+ formatToParts(count, unit) {
46435
+ if (this.rtf) {
46436
+ return this.rtf.formatToParts(count, unit);
46536
46437
  } else {
46537
- return this.reason;
46438
+ return [];
46538
46439
  }
46539
46440
  }
46540
46441
 
46541
46442
  }
46542
-
46543
46443
  /**
46544
- * @interface
46444
+ * @private
46545
46445
  */
46546
46446
 
46547
- class Zone {
46548
- /**
46549
- * The type of zone
46550
- * @abstract
46551
- * @type {string}
46552
- */
46553
- get type() {
46554
- throw new ZoneIsAbstractError();
46447
+
46448
+ class Locale {
46449
+ static fromOpts(opts) {
46450
+ return Locale.create(opts.locale, opts.numberingSystem, opts.outputCalendar, opts.defaultToEN);
46555
46451
  }
46556
- /**
46557
- * The name of this zone.
46558
- * @abstract
46559
- * @type {string}
46560
- */
46561
46452
 
46453
+ static create(locale, numberingSystem, outputCalendar, defaultToEN = false) {
46454
+ const specifiedLocale = locale || Settings.defaultLocale; // the system locale is useful for human readable strings but annoying for parsing/formatting known formats
46562
46455
 
46563
- get name() {
46564
- throw new ZoneIsAbstractError();
46456
+ const localeR = specifiedLocale || (defaultToEN ? "en-US" : systemLocale());
46457
+ const numberingSystemR = numberingSystem || Settings.defaultNumberingSystem;
46458
+ const outputCalendarR = outputCalendar || Settings.defaultOutputCalendar;
46459
+ return new Locale(localeR, numberingSystemR, outputCalendarR, specifiedLocale);
46565
46460
  }
46566
46461
 
46567
- get ianaName() {
46568
- return this.name;
46462
+ static resetCache() {
46463
+ sysLocaleCache = null;
46464
+ intlDTCache = {};
46465
+ intlNumCache = {};
46466
+ intlRelCache = {};
46569
46467
  }
46570
- /**
46571
- * Returns whether the offset is known to be fixed for the whole year.
46572
- * @abstract
46573
- * @type {boolean}
46574
- */
46575
-
46576
46468
 
46577
- get isUniversal() {
46578
- throw new ZoneIsAbstractError();
46469
+ static fromObject({
46470
+ locale,
46471
+ numberingSystem,
46472
+ outputCalendar
46473
+ } = {}) {
46474
+ return Locale.create(locale, numberingSystem, outputCalendar);
46579
46475
  }
46580
- /**
46581
- * Returns the offset's common name (such as EST) at the specified timestamp
46582
- * @abstract
46583
- * @param {number} ts - Epoch milliseconds for which to get the name
46584
- * @param {Object} opts - Options to affect the format
46585
- * @param {string} opts.format - What style of offset to return. Accepts 'long' or 'short'.
46586
- * @param {string} opts.locale - What locale to return the offset name in.
46587
- * @return {string}
46588
- */
46589
-
46590
46476
 
46591
- offsetName(ts, opts) {
46592
- throw new ZoneIsAbstractError();
46477
+ constructor(locale, numbering, outputCalendar, specifiedLocale) {
46478
+ const [parsedLocale, parsedNumberingSystem, parsedOutputCalendar] = parseLocaleString(locale);
46479
+ this.locale = parsedLocale;
46480
+ this.numberingSystem = numbering || parsedNumberingSystem || null;
46481
+ this.outputCalendar = outputCalendar || parsedOutputCalendar || null;
46482
+ this.intl = intlConfigString(this.locale, this.numberingSystem, this.outputCalendar);
46483
+ this.weekdaysCache = {
46484
+ format: {},
46485
+ standalone: {}
46486
+ };
46487
+ this.monthsCache = {
46488
+ format: {},
46489
+ standalone: {}
46490
+ };
46491
+ this.meridiemCache = null;
46492
+ this.eraCache = {};
46493
+ this.specifiedLocale = specifiedLocale;
46494
+ this.fastNumbersCached = null;
46593
46495
  }
46594
- /**
46595
- * Returns the offset's value as a string
46596
- * @abstract
46597
- * @param {number} ts - Epoch milliseconds for which to get the offset
46598
- * @param {string} format - What style of offset to return.
46599
- * Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively
46600
- * @return {string}
46601
- */
46602
46496
 
46497
+ get fastNumbers() {
46498
+ if (this.fastNumbersCached == null) {
46499
+ this.fastNumbersCached = supportsFastNumbers(this);
46500
+ }
46603
46501
 
46604
- formatOffset(ts, format) {
46605
- throw new ZoneIsAbstractError();
46502
+ return this.fastNumbersCached;
46606
46503
  }
46607
- /**
46608
- * Return the offset in minutes for this zone at the specified timestamp.
46609
- * @abstract
46610
- * @param {number} ts - Epoch milliseconds for which to compute the offset
46611
- * @return {number}
46612
- */
46613
-
46614
46504
 
46615
- offset(ts) {
46616
- throw new ZoneIsAbstractError();
46505
+ listingMode() {
46506
+ const isActuallyEn = this.isEnglish();
46507
+ const hasNoWeirdness = (this.numberingSystem === null || this.numberingSystem === "latn") && (this.outputCalendar === null || this.outputCalendar === "gregory");
46508
+ return isActuallyEn && hasNoWeirdness ? "en" : "intl";
46617
46509
  }
46618
- /**
46619
- * Return whether this Zone is equal to another zone
46620
- * @abstract
46621
- * @param {Zone} otherZone - the zone to compare
46622
- * @return {boolean}
46623
- */
46624
46510
 
46625
-
46626
- equals(otherZone) {
46627
- throw new ZoneIsAbstractError();
46511
+ clone(alts) {
46512
+ if (!alts || Object.getOwnPropertyNames(alts).length === 0) {
46513
+ return this;
46514
+ } else {
46515
+ return Locale.create(alts.locale || this.specifiedLocale, alts.numberingSystem || this.numberingSystem, alts.outputCalendar || this.outputCalendar, alts.defaultToEN || false);
46516
+ }
46628
46517
  }
46629
- /**
46630
- * Return whether this Zone is valid.
46631
- * @abstract
46632
- * @type {boolean}
46633
- */
46634
46518
 
46635
-
46636
- get isValid() {
46637
- throw new ZoneIsAbstractError();
46519
+ redefaultToEN(alts = {}) {
46520
+ return this.clone({ ...alts,
46521
+ defaultToEN: true
46522
+ });
46638
46523
  }
46639
46524
 
46640
- }
46525
+ redefaultToSystem(alts = {}) {
46526
+ return this.clone({ ...alts,
46527
+ defaultToEN: false
46528
+ });
46529
+ }
46641
46530
 
46642
- let singleton$1 = null;
46643
- /**
46644
- * Represents the local zone for this JavaScript environment.
46645
- * @implements {Zone}
46646
- */
46531
+ months(length, format = false, defaultOK = true) {
46532
+ return listStuff(this, length, defaultOK, months, () => {
46533
+ const intl = format ? {
46534
+ month: length,
46535
+ day: "numeric"
46536
+ } : {
46537
+ month: length
46538
+ },
46539
+ formatStr = format ? "format" : "standalone";
46647
46540
 
46648
- class SystemZone extends Zone {
46649
- /**
46650
- * Get a singleton instance of the local zone
46651
- * @return {SystemZone}
46652
- */
46653
- static get instance() {
46654
- if (singleton$1 === null) {
46655
- singleton$1 = new SystemZone();
46656
- }
46541
+ if (!this.monthsCache[formatStr][length]) {
46542
+ this.monthsCache[formatStr][length] = mapMonths(dt => this.extract(dt, intl, "month"));
46543
+ }
46657
46544
 
46658
- return singleton$1;
46545
+ return this.monthsCache[formatStr][length];
46546
+ });
46659
46547
  }
46660
- /** @override **/
46661
-
46662
46548
 
46663
- get type() {
46664
- return "system";
46665
- }
46666
- /** @override **/
46549
+ weekdays(length, format = false, defaultOK = true) {
46550
+ return listStuff(this, length, defaultOK, weekdays, () => {
46551
+ const intl = format ? {
46552
+ weekday: length,
46553
+ year: "numeric",
46554
+ month: "long",
46555
+ day: "numeric"
46556
+ } : {
46557
+ weekday: length
46558
+ },
46559
+ formatStr = format ? "format" : "standalone";
46667
46560
 
46561
+ if (!this.weekdaysCache[formatStr][length]) {
46562
+ this.weekdaysCache[formatStr][length] = mapWeekdays(dt => this.extract(dt, intl, "weekday"));
46563
+ }
46668
46564
 
46669
- get name() {
46670
- return new Intl.DateTimeFormat().resolvedOptions().timeZone;
46565
+ return this.weekdaysCache[formatStr][length];
46566
+ });
46671
46567
  }
46672
- /** @override **/
46673
46568
 
46569
+ meridiems(defaultOK = true) {
46570
+ return listStuff(this, undefined, defaultOK, () => meridiems, () => {
46571
+ // In theory there could be aribitrary day periods. We're gonna assume there are exactly two
46572
+ // for AM and PM. This is probably wrong, but it's makes parsing way easier.
46573
+ if (!this.meridiemCache) {
46574
+ const intl = {
46575
+ hour: "numeric",
46576
+ hourCycle: "h12"
46577
+ };
46578
+ this.meridiemCache = [DateTime.utc(2016, 11, 13, 9), DateTime.utc(2016, 11, 13, 19)].map(dt => this.extract(dt, intl, "dayperiod"));
46579
+ }
46674
46580
 
46675
- get isUniversal() {
46676
- return false;
46581
+ return this.meridiemCache;
46582
+ });
46677
46583
  }
46678
- /** @override **/
46679
46584
 
46585
+ eras(length, defaultOK = true) {
46586
+ return listStuff(this, length, defaultOK, eras, () => {
46587
+ const intl = {
46588
+ era: length
46589
+ }; // This is problematic. Different calendars are going to define eras totally differently. What I need is the minimum set of dates
46590
+ // to definitely enumerate them.
46591
+
46592
+ if (!this.eraCache[length]) {
46593
+ this.eraCache[length] = [DateTime.utc(-40, 1, 1), DateTime.utc(2017, 1, 1)].map(dt => this.extract(dt, intl, "era"));
46594
+ }
46680
46595
 
46681
- offsetName(ts, {
46682
- format,
46683
- locale
46684
- }) {
46685
- return parseZoneInfo(ts, format, locale);
46596
+ return this.eraCache[length];
46597
+ });
46686
46598
  }
46687
- /** @override **/
46688
-
46689
46599
 
46690
- formatOffset(ts, format) {
46691
- return formatOffset(this.offset(ts), format);
46600
+ extract(dt, intlOpts, field) {
46601
+ const df = this.dtFormatter(dt, intlOpts),
46602
+ results = df.formatToParts(),
46603
+ matching = results.find(m => m.type.toLowerCase() === field);
46604
+ return matching ? matching.value : null;
46692
46605
  }
46693
- /** @override **/
46694
46606
 
46607
+ numberFormatter(opts = {}) {
46608
+ // this forcesimple option is never used (the only caller short-circuits on it, but it seems safer to leave)
46609
+ // (in contrast, the rest of the condition is used heavily)
46610
+ return new PolyNumberFormatter(this.intl, opts.forceSimple || this.fastNumbers, opts);
46611
+ }
46695
46612
 
46696
- offset(ts) {
46697
- return -new Date(ts).getTimezoneOffset();
46613
+ dtFormatter(dt, intlOpts = {}) {
46614
+ return new PolyDateFormatter(dt, this.intl, intlOpts);
46698
46615
  }
46699
- /** @override **/
46700
46616
 
46617
+ relFormatter(opts = {}) {
46618
+ return new PolyRelFormatter(this.intl, this.isEnglish(), opts);
46619
+ }
46701
46620
 
46702
- equals(otherZone) {
46703
- return otherZone.type === "system";
46621
+ listFormatter(opts = {}) {
46622
+ return getCachedLF(this.intl, opts);
46704
46623
  }
46705
- /** @override **/
46706
46624
 
46625
+ isEnglish() {
46626
+ return this.locale === "en" || this.locale.toLowerCase() === "en-us" || new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us");
46627
+ }
46707
46628
 
46708
- get isValid() {
46709
- return true;
46710
- }
46711
-
46712
- }
46713
-
46714
- let dtfCache = {};
46715
-
46716
- function makeDTF(zone) {
46717
- if (!dtfCache[zone]) {
46718
- dtfCache[zone] = new Intl.DateTimeFormat("en-US", {
46719
- hour12: false,
46720
- timeZone: zone,
46721
- year: "numeric",
46722
- month: "2-digit",
46723
- day: "2-digit",
46724
- hour: "2-digit",
46725
- minute: "2-digit",
46726
- second: "2-digit",
46727
- era: "short"
46728
- });
46729
- }
46730
-
46731
- return dtfCache[zone];
46732
- }
46733
-
46734
- const typeToPos = {
46735
- year: 0,
46736
- month: 1,
46737
- day: 2,
46738
- era: 3,
46739
- hour: 4,
46740
- minute: 5,
46741
- second: 6
46742
- };
46743
-
46744
- function hackyOffset(dtf, date) {
46745
- const formatted = dtf.format(date).replace(/\u200E/g, ""),
46746
- parsed = /(\d+)\/(\d+)\/(\d+) (AD|BC),? (\d+):(\d+):(\d+)/.exec(formatted),
46747
- [, fMonth, fDay, fYear, fadOrBc, fHour, fMinute, fSecond] = parsed;
46748
- return [fYear, fMonth, fDay, fadOrBc, fHour, fMinute, fSecond];
46749
- }
46750
-
46751
- function partsOffset(dtf, date) {
46752
- const formatted = dtf.formatToParts(date);
46753
- const filled = [];
46754
-
46755
- for (let i = 0; i < formatted.length; i++) {
46756
- const {
46757
- type,
46758
- value
46759
- } = formatted[i];
46760
- const pos = typeToPos[type];
46761
-
46762
- if (type === "era") {
46763
- filled[pos] = value;
46764
- } else if (!isUndefined(pos)) {
46765
- filled[pos] = parseInt(value, 10);
46766
- }
46767
- }
46768
-
46769
- return filled;
46770
- }
46771
-
46772
- let ianaZoneCache = {};
46773
- /**
46774
- * A zone identified by an IANA identifier, like America/New_York
46775
- * @implements {Zone}
46776
- */
46777
-
46778
- class IANAZone extends Zone {
46779
- /**
46780
- * @param {string} name - Zone name
46781
- * @return {IANAZone}
46782
- */
46783
- static create(name) {
46784
- if (!ianaZoneCache[name]) {
46785
- ianaZoneCache[name] = new IANAZone(name);
46786
- }
46787
-
46788
- return ianaZoneCache[name];
46789
- }
46790
- /**
46791
- * Reset local caches. Should only be necessary in testing scenarios.
46792
- * @return {void}
46793
- */
46794
-
46795
-
46796
- static resetCache() {
46797
- ianaZoneCache = {};
46798
- dtfCache = {};
46799
- }
46800
- /**
46801
- * Returns whether the provided string is a valid specifier. This only checks the string's format, not that the specifier identifies a known zone; see isValidZone for that.
46802
- * @param {string} s - The string to check validity on
46803
- * @example IANAZone.isValidSpecifier("America/New_York") //=> true
46804
- * @example IANAZone.isValidSpecifier("Sport~~blorp") //=> false
46805
- * @deprecated This method returns false for some valid IANA names. Use isValidZone instead.
46806
- * @return {boolean}
46807
- */
46808
-
46809
-
46810
- static isValidSpecifier(s) {
46811
- return this.isValidZone(s);
46812
- }
46813
- /**
46814
- * Returns whether the provided string identifies a real zone
46815
- * @param {string} zone - The string to check
46816
- * @example IANAZone.isValidZone("America/New_York") //=> true
46817
- * @example IANAZone.isValidZone("Fantasia/Castle") //=> false
46818
- * @example IANAZone.isValidZone("Sport~~blorp") //=> false
46819
- * @return {boolean}
46820
- */
46821
-
46822
-
46823
- static isValidZone(zone) {
46824
- if (!zone) {
46825
- return false;
46826
- }
46827
-
46828
- try {
46829
- new Intl.DateTimeFormat("en-US", {
46830
- timeZone: zone
46831
- }).format();
46832
- return true;
46833
- } catch (e) {
46834
- return false;
46835
- }
46836
- }
46837
-
46838
- constructor(name) {
46839
- super();
46840
- /** @private **/
46841
-
46842
- this.zoneName = name;
46843
- /** @private **/
46844
-
46845
- this.valid = IANAZone.isValidZone(name);
46846
- }
46847
- /** @override **/
46848
-
46849
-
46850
- get type() {
46851
- return "iana";
46852
- }
46853
- /** @override **/
46854
-
46855
-
46856
- get name() {
46857
- return this.zoneName;
46858
- }
46859
- /** @override **/
46860
-
46861
-
46862
- get isUniversal() {
46863
- return false;
46864
- }
46865
- /** @override **/
46866
-
46867
-
46868
- offsetName(ts, {
46869
- format,
46870
- locale
46871
- }) {
46872
- return parseZoneInfo(ts, format, locale, this.name);
46873
- }
46874
- /** @override **/
46875
-
46876
-
46877
- formatOffset(ts, format) {
46878
- return formatOffset(this.offset(ts), format);
46879
- }
46880
- /** @override **/
46881
-
46882
-
46883
- offset(ts) {
46884
- const date = new Date(ts);
46885
- if (isNaN(date)) return NaN;
46886
- const dtf = makeDTF(this.name);
46887
- let [year, month, day, adOrBc, hour, minute, second] = dtf.formatToParts ? partsOffset(dtf, date) : hackyOffset(dtf, date);
46888
-
46889
- if (adOrBc === "BC") {
46890
- year = -Math.abs(year) + 1;
46891
- } // because we're using hour12 and https://bugs.chromium.org/p/chromium/issues/detail?id=1025564&can=2&q=%2224%3A00%22%20datetimeformat
46892
-
46893
-
46894
- const adjustedHour = hour === 24 ? 0 : hour;
46895
- const asUTC = objToLocalTS({
46896
- year,
46897
- month,
46898
- day,
46899
- hour: adjustedHour,
46900
- minute,
46901
- second,
46902
- millisecond: 0
46903
- });
46904
- let asTS = +date;
46905
- const over = asTS % 1000;
46906
- asTS -= over >= 0 ? over : 1000 + over;
46907
- return (asUTC - asTS) / (60 * 1000);
46908
- }
46909
- /** @override **/
46910
-
46911
-
46912
- equals(otherZone) {
46913
- return otherZone.type === "iana" && otherZone.name === this.name;
46914
- }
46915
- /** @override **/
46916
-
46917
-
46918
- get isValid() {
46919
- return this.valid;
46629
+ equals(other) {
46630
+ return this.locale === other.locale && this.numberingSystem === other.numberingSystem && this.outputCalendar === other.outputCalendar;
46920
46631
  }
46921
46632
 
46922
46633
  }
@@ -47127,6 +46838,7 @@ let now = () => Date.now(),
47127
46838
  defaultLocale = null,
47128
46839
  defaultNumberingSystem = null,
47129
46840
  defaultOutputCalendar = null,
46841
+ twoDigitCutoffYear = 60,
47130
46842
  throwOnInvalid;
47131
46843
  /**
47132
46844
  * Settings contains static getters and setters that control Luxon's overall behavior. Luxon is a simple library with few options, but the ones it does have live here.
@@ -47227,6 +46939,28 @@ class Settings {
47227
46939
  static set defaultOutputCalendar(outputCalendar) {
47228
46940
  defaultOutputCalendar = outputCalendar;
47229
46941
  }
46942
+ /**
46943
+ * Get the cutoff year after which a string encoding a year as two digits is interpreted to occur in the current century.
46944
+ * @type {number}
46945
+ */
46946
+
46947
+
46948
+ static get twoDigitCutoffYear() {
46949
+ return twoDigitCutoffYear;
46950
+ }
46951
+ /**
46952
+ * Set the cutoff year after which a string encoding a year as two digits is interpreted to occur in the current century.
46953
+ * @type {number}
46954
+ * @example Settings.twoDigitCutoffYear = 0 // cut-off year is 0, so all 'yy' are interpretted as current century
46955
+ * @example Settings.twoDigitCutoffYear = 50 // '49' -> 1949; '50' -> 2050
46956
+ * @example Settings.twoDigitCutoffYear = 1950 // interpretted as 50
46957
+ * @example Settings.twoDigitCutoffYear = 2050 // ALSO interpretted as 50
46958
+ */
46959
+
46960
+
46961
+ static set twoDigitCutoffYear(cutoffYear) {
46962
+ twoDigitCutoffYear = cutoffYear % 100;
46963
+ }
47230
46964
  /**
47231
46965
  * Get whether Luxon will throw when it encounters invalid DateTimes, Durations, or Intervals
47232
46966
  * @type {boolean}
@@ -47258,495 +46992,870 @@ class Settings {
47258
46992
 
47259
46993
  }
47260
46994
 
47261
- let intlLFCache = {};
46995
+ /*
46996
+ This is just a junk drawer, containing anything used across multiple classes.
46997
+ Because Luxon is small(ish), this should stay small and we won't worry about splitting
46998
+ it up into, say, parsingUtil.js and basicUtil.js and so on. But they are divided up by feature area.
46999
+ */
47000
+ /**
47001
+ * @private
47002
+ */
47003
+ // TYPES
47262
47004
 
47263
- function getCachedLF(locString, opts = {}) {
47264
- const key = JSON.stringify([locString, opts]);
47265
- let dtf = intlLFCache[key];
47005
+ function isUndefined(o) {
47006
+ return typeof o === "undefined";
47007
+ }
47008
+ function isNumber(o) {
47009
+ return typeof o === "number";
47010
+ }
47011
+ function isInteger(o) {
47012
+ return typeof o === "number" && o % 1 === 0;
47013
+ }
47014
+ function isString(o) {
47015
+ return typeof o === "string";
47016
+ }
47017
+ function isDate(o) {
47018
+ return Object.prototype.toString.call(o) === "[object Date]";
47019
+ } // CAPABILITIES
47266
47020
 
47267
- if (!dtf) {
47268
- dtf = new Intl.ListFormat(locString, opts);
47269
- intlLFCache[key] = dtf;
47021
+ function hasRelative() {
47022
+ try {
47023
+ return typeof Intl !== "undefined" && !!Intl.RelativeTimeFormat;
47024
+ } catch (e) {
47025
+ return false;
47270
47026
  }
47027
+ } // OBJECTS AND ARRAYS
47271
47028
 
47272
- return dtf;
47029
+ function maybeArray(thing) {
47030
+ return Array.isArray(thing) ? thing : [thing];
47031
+ }
47032
+ function bestBy(arr, by, compare) {
47033
+ if (arr.length === 0) {
47034
+ return undefined;
47035
+ }
47036
+
47037
+ return arr.reduce((best, next) => {
47038
+ const pair = [by(next), next];
47039
+
47040
+ if (!best) {
47041
+ return pair;
47042
+ } else if (compare(best[0], pair[0]) === best[0]) {
47043
+ return best;
47044
+ } else {
47045
+ return pair;
47046
+ }
47047
+ }, null)[1];
47273
47048
  }
47049
+ function pick(obj, keys) {
47050
+ return keys.reduce((a, k) => {
47051
+ a[k] = obj[k];
47052
+ return a;
47053
+ }, {});
47054
+ }
47055
+ function hasOwnProperty(obj, prop) {
47056
+ return Object.prototype.hasOwnProperty.call(obj, prop);
47057
+ } // NUMBERS AND STRINGS
47274
47058
 
47275
- let intlDTCache = {};
47059
+ function integerBetween(thing, bottom, top) {
47060
+ return isInteger(thing) && thing >= bottom && thing <= top;
47061
+ } // x % n but takes the sign of n instead of x
47276
47062
 
47277
- function getCachedDTF(locString, opts = {}) {
47278
- const key = JSON.stringify([locString, opts]);
47279
- let dtf = intlDTCache[key];
47063
+ function floorMod(x, n) {
47064
+ return x - n * Math.floor(x / n);
47065
+ }
47066
+ function padStart(input, n = 2) {
47067
+ const isNeg = input < 0;
47068
+ let padded;
47280
47069
 
47281
- if (!dtf) {
47282
- dtf = new Intl.DateTimeFormat(locString, opts);
47283
- intlDTCache[key] = dtf;
47070
+ if (isNeg) {
47071
+ padded = "-" + ("" + -input).padStart(n, "0");
47072
+ } else {
47073
+ padded = ("" + input).padStart(n, "0");
47284
47074
  }
47285
47075
 
47286
- return dtf;
47076
+ return padded;
47287
47077
  }
47078
+ function parseInteger(string) {
47079
+ if (isUndefined(string) || string === null || string === "") {
47080
+ return undefined;
47081
+ } else {
47082
+ return parseInt(string, 10);
47083
+ }
47084
+ }
47085
+ function parseFloating(string) {
47086
+ if (isUndefined(string) || string === null || string === "") {
47087
+ return undefined;
47088
+ } else {
47089
+ return parseFloat(string);
47090
+ }
47091
+ }
47092
+ function parseMillis(fraction) {
47093
+ // Return undefined (instead of 0) in these cases, where fraction is not set
47094
+ if (isUndefined(fraction) || fraction === null || fraction === "") {
47095
+ return undefined;
47096
+ } else {
47097
+ const f = parseFloat("0." + fraction) * 1000;
47098
+ return Math.floor(f);
47099
+ }
47100
+ }
47101
+ function roundTo(number, digits, towardZero = false) {
47102
+ const factor = 10 ** digits,
47103
+ rounder = towardZero ? Math.trunc : Math.round;
47104
+ return rounder(number * factor) / factor;
47105
+ } // DATE BASICS
47288
47106
 
47289
- let intlNumCache = {};
47107
+ function isLeapYear(year) {
47108
+ return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
47109
+ }
47110
+ function daysInYear(year) {
47111
+ return isLeapYear(year) ? 366 : 365;
47112
+ }
47113
+ function daysInMonth(year, month) {
47114
+ const modMonth = floorMod(month - 1, 12) + 1,
47115
+ modYear = year + (month - modMonth) / 12;
47290
47116
 
47291
- function getCachedINF(locString, opts = {}) {
47292
- const key = JSON.stringify([locString, opts]);
47293
- let inf = intlNumCache[key];
47117
+ if (modMonth === 2) {
47118
+ return isLeapYear(modYear) ? 29 : 28;
47119
+ } else {
47120
+ return [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][modMonth - 1];
47121
+ }
47122
+ } // covert a calendar object to a local timestamp (epoch, but with the offset baked in)
47294
47123
 
47295
- if (!inf) {
47296
- inf = new Intl.NumberFormat(locString, opts);
47297
- intlNumCache[key] = inf;
47124
+ function objToLocalTS(obj) {
47125
+ let d = Date.UTC(obj.year, obj.month - 1, obj.day, obj.hour, obj.minute, obj.second, obj.millisecond); // for legacy reasons, years between 0 and 99 are interpreted as 19XX; revert that
47126
+
47127
+ if (obj.year < 100 && obj.year >= 0) {
47128
+ d = new Date(d);
47129
+ d.setUTCFullYear(d.getUTCFullYear() - 1900);
47298
47130
  }
47299
47131
 
47300
- return inf;
47132
+ return +d;
47301
47133
  }
47134
+ function weeksInWeekYear(weekYear) {
47135
+ const p1 = (weekYear + Math.floor(weekYear / 4) - Math.floor(weekYear / 100) + Math.floor(weekYear / 400)) % 7,
47136
+ last = weekYear - 1,
47137
+ p2 = (last + Math.floor(last / 4) - Math.floor(last / 100) + Math.floor(last / 400)) % 7;
47138
+ return p1 === 4 || p2 === 3 ? 53 : 52;
47139
+ }
47140
+ function untruncateYear(year) {
47141
+ if (year > 99) {
47142
+ return year;
47143
+ } else return year > Settings.twoDigitCutoffYear ? 1900 + year : 2000 + year;
47144
+ } // PARSING
47302
47145
 
47303
- let intlRelCache = {};
47146
+ function parseZoneInfo(ts, offsetFormat, locale, timeZone = null) {
47147
+ const date = new Date(ts),
47148
+ intlOpts = {
47149
+ hourCycle: "h23",
47150
+ year: "numeric",
47151
+ month: "2-digit",
47152
+ day: "2-digit",
47153
+ hour: "2-digit",
47154
+ minute: "2-digit"
47155
+ };
47304
47156
 
47305
- function getCachedRTF(locString, opts = {}) {
47306
- const {
47307
- base,
47308
- ...cacheKeyOpts
47309
- } = opts; // exclude `base` from the options
47157
+ if (timeZone) {
47158
+ intlOpts.timeZone = timeZone;
47159
+ }
47310
47160
 
47311
- const key = JSON.stringify([locString, cacheKeyOpts]);
47312
- let inf = intlRelCache[key];
47161
+ const modified = {
47162
+ timeZoneName: offsetFormat,
47163
+ ...intlOpts
47164
+ };
47165
+ const parsed = new Intl.DateTimeFormat(locale, modified).formatToParts(date).find(m => m.type.toLowerCase() === "timezonename");
47166
+ return parsed ? parsed.value : null;
47167
+ } // signedOffset('-5', '30') -> -330
47313
47168
 
47314
- if (!inf) {
47315
- inf = new Intl.RelativeTimeFormat(locString, opts);
47316
- intlRelCache[key] = inf;
47169
+ function signedOffset(offHourStr, offMinuteStr) {
47170
+ let offHour = parseInt(offHourStr, 10); // don't || this because we want to preserve -0
47171
+
47172
+ if (Number.isNaN(offHour)) {
47173
+ offHour = 0;
47317
47174
  }
47318
47175
 
47319
- return inf;
47176
+ const offMin = parseInt(offMinuteStr, 10) || 0,
47177
+ offMinSigned = offHour < 0 || Object.is(offHour, -0) ? -offMin : offMin;
47178
+ return offHour * 60 + offMinSigned;
47179
+ } // COERCION
47180
+
47181
+ function asNumber(value) {
47182
+ const numericValue = Number(value);
47183
+ if (typeof value === "boolean" || value === "" || Number.isNaN(numericValue)) throw new InvalidArgumentError(`Invalid unit value ${value}`);
47184
+ return numericValue;
47320
47185
  }
47186
+ function normalizeObject(obj, normalizer) {
47187
+ const normalized = {};
47321
47188
 
47322
- let sysLocaleCache = null;
47189
+ for (const u in obj) {
47190
+ if (hasOwnProperty(obj, u)) {
47191
+ const v = obj[u];
47192
+ if (v === undefined || v === null) continue;
47193
+ normalized[normalizer(u)] = asNumber(v);
47194
+ }
47195
+ }
47323
47196
 
47324
- function systemLocale() {
47325
- if (sysLocaleCache) {
47326
- return sysLocaleCache;
47327
- } else {
47328
- sysLocaleCache = new Intl.DateTimeFormat().resolvedOptions().locale;
47329
- return sysLocaleCache;
47197
+ return normalized;
47198
+ }
47199
+ function formatOffset(offset, format) {
47200
+ const hours = Math.trunc(Math.abs(offset / 60)),
47201
+ minutes = Math.trunc(Math.abs(offset % 60)),
47202
+ sign = offset >= 0 ? "+" : "-";
47203
+
47204
+ switch (format) {
47205
+ case "short":
47206
+ return `${sign}${padStart(hours, 2)}:${padStart(minutes, 2)}`;
47207
+
47208
+ case "narrow":
47209
+ return `${sign}${hours}${minutes > 0 ? `:${minutes}` : ""}`;
47210
+
47211
+ case "techie":
47212
+ return `${sign}${padStart(hours, 2)}${padStart(minutes, 2)}`;
47213
+
47214
+ default:
47215
+ throw new RangeError(`Value format ${format} is out of range for property format`);
47330
47216
  }
47331
47217
  }
47218
+ function timeObject(obj) {
47219
+ return pick(obj, ["hour", "minute", "second", "millisecond"]);
47220
+ }
47332
47221
 
47333
- function parseLocaleString(localeStr) {
47334
- // I really want to avoid writing a BCP 47 parser
47335
- // see, e.g. https://github.com/wooorm/bcp-47
47336
- // Instead, we'll do this:
47337
- // a) if the string has no -u extensions, just leave it alone
47338
- // b) if it does, use Intl to resolve everything
47339
- // c) if Intl fails, try again without the -u
47340
- const uIndex = localeStr.indexOf("-u-");
47222
+ /**
47223
+ * @private
47224
+ */
47341
47225
 
47342
- if (uIndex === -1) {
47343
- return [localeStr];
47344
- } else {
47345
- let options;
47346
- const smaller = localeStr.substring(0, uIndex);
47347
47226
 
47348
- try {
47349
- options = getCachedDTF(localeStr).resolvedOptions();
47350
- } catch (e) {
47351
- options = getCachedDTF(smaller).resolvedOptions();
47227
+ const monthsLong = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
47228
+ const monthsShort = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
47229
+ const monthsNarrow = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"];
47230
+ function months(length) {
47231
+ switch (length) {
47232
+ case "narrow":
47233
+ return [...monthsNarrow];
47234
+
47235
+ case "short":
47236
+ return [...monthsShort];
47237
+
47238
+ case "long":
47239
+ return [...monthsLong];
47240
+
47241
+ case "numeric":
47242
+ return ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
47243
+
47244
+ case "2-digit":
47245
+ return ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"];
47246
+
47247
+ default:
47248
+ return null;
47249
+ }
47250
+ }
47251
+ const weekdaysLong = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
47252
+ const weekdaysShort = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
47253
+ const weekdaysNarrow = ["M", "T", "W", "T", "F", "S", "S"];
47254
+ function weekdays(length) {
47255
+ switch (length) {
47256
+ case "narrow":
47257
+ return [...weekdaysNarrow];
47258
+
47259
+ case "short":
47260
+ return [...weekdaysShort];
47261
+
47262
+ case "long":
47263
+ return [...weekdaysLong];
47264
+
47265
+ case "numeric":
47266
+ return ["1", "2", "3", "4", "5", "6", "7"];
47267
+
47268
+ default:
47269
+ return null;
47270
+ }
47271
+ }
47272
+ const meridiems = ["AM", "PM"];
47273
+ const erasLong = ["Before Christ", "Anno Domini"];
47274
+ const erasShort = ["BC", "AD"];
47275
+ const erasNarrow = ["B", "A"];
47276
+ function eras(length) {
47277
+ switch (length) {
47278
+ case "narrow":
47279
+ return [...erasNarrow];
47280
+
47281
+ case "short":
47282
+ return [...erasShort];
47283
+
47284
+ case "long":
47285
+ return [...erasLong];
47286
+
47287
+ default:
47288
+ return null;
47289
+ }
47290
+ }
47291
+ function meridiemForDateTime(dt) {
47292
+ return meridiems[dt.hour < 12 ? 0 : 1];
47293
+ }
47294
+ function weekdayForDateTime(dt, length) {
47295
+ return weekdays(length)[dt.weekday - 1];
47296
+ }
47297
+ function monthForDateTime(dt, length) {
47298
+ return months(length)[dt.month - 1];
47299
+ }
47300
+ function eraForDateTime(dt, length) {
47301
+ return eras(length)[dt.year < 0 ? 0 : 1];
47302
+ }
47303
+ function formatRelativeTime(unit, count, numeric = "always", narrow = false) {
47304
+ const units = {
47305
+ years: ["year", "yr."],
47306
+ quarters: ["quarter", "qtr."],
47307
+ months: ["month", "mo."],
47308
+ weeks: ["week", "wk."],
47309
+ days: ["day", "day", "days"],
47310
+ hours: ["hour", "hr."],
47311
+ minutes: ["minute", "min."],
47312
+ seconds: ["second", "sec."]
47313
+ };
47314
+ const lastable = ["hours", "minutes", "seconds"].indexOf(unit) === -1;
47315
+
47316
+ if (numeric === "auto" && lastable) {
47317
+ const isDay = unit === "days";
47318
+
47319
+ switch (count) {
47320
+ case 1:
47321
+ return isDay ? "tomorrow" : `next ${units[unit][0]}`;
47322
+
47323
+ case -1:
47324
+ return isDay ? "yesterday" : `last ${units[unit][0]}`;
47325
+
47326
+ case 0:
47327
+ return isDay ? "today" : `this ${units[unit][0]}`;
47328
+
47352
47329
  }
47330
+ }
47353
47331
 
47354
- const {
47355
- numberingSystem,
47356
- calendar
47357
- } = options; // return the smaller one so that we can append the calendar and numbering overrides to it
47332
+ const isInPast = Object.is(count, -0) || count < 0,
47333
+ fmtValue = Math.abs(count),
47334
+ singular = fmtValue === 1,
47335
+ lilUnits = units[unit],
47336
+ fmtUnit = narrow ? singular ? lilUnits[1] : lilUnits[2] || lilUnits[1] : singular ? units[unit][0] : unit;
47337
+ return isInPast ? `${fmtValue} ${fmtUnit} ago` : `in ${fmtValue} ${fmtUnit}`;
47338
+ }
47358
47339
 
47359
- return [smaller, numberingSystem, calendar];
47340
+ function stringifyTokens(splits, tokenToString) {
47341
+ let s = "";
47342
+
47343
+ for (const token of splits) {
47344
+ if (token.literal) {
47345
+ s += token.val;
47346
+ } else {
47347
+ s += tokenToString(token.val);
47348
+ }
47360
47349
  }
47350
+
47351
+ return s;
47361
47352
  }
47362
47353
 
47363
- function intlConfigString(localeStr, numberingSystem, outputCalendar) {
47364
- if (outputCalendar || numberingSystem) {
47365
- localeStr += "-u";
47354
+ const macroTokenToFormatOpts = {
47355
+ D: DATE_SHORT,
47356
+ DD: DATE_MED,
47357
+ DDD: DATE_FULL,
47358
+ DDDD: DATE_HUGE,
47359
+ t: TIME_SIMPLE,
47360
+ tt: TIME_WITH_SECONDS,
47361
+ ttt: TIME_WITH_SHORT_OFFSET,
47362
+ tttt: TIME_WITH_LONG_OFFSET,
47363
+ T: TIME_24_SIMPLE,
47364
+ TT: TIME_24_WITH_SECONDS,
47365
+ TTT: TIME_24_WITH_SHORT_OFFSET,
47366
+ TTTT: TIME_24_WITH_LONG_OFFSET,
47367
+ f: DATETIME_SHORT,
47368
+ ff: DATETIME_MED,
47369
+ fff: DATETIME_FULL,
47370
+ ffff: DATETIME_HUGE,
47371
+ F: DATETIME_SHORT_WITH_SECONDS,
47372
+ FF: DATETIME_MED_WITH_SECONDS,
47373
+ FFF: DATETIME_FULL_WITH_SECONDS,
47374
+ FFFF: DATETIME_HUGE_WITH_SECONDS
47375
+ };
47376
+ /**
47377
+ * @private
47378
+ */
47366
47379
 
47367
- if (outputCalendar) {
47368
- localeStr += `-ca-${outputCalendar}`;
47380
+ class Formatter {
47381
+ static create(locale, opts = {}) {
47382
+ return new Formatter(locale, opts);
47383
+ }
47384
+
47385
+ static parseFormat(fmt) {
47386
+ let current = null,
47387
+ currentFull = "",
47388
+ bracketed = false;
47389
+ const splits = [];
47390
+
47391
+ for (let i = 0; i < fmt.length; i++) {
47392
+ const c = fmt.charAt(i);
47393
+
47394
+ if (c === "'") {
47395
+ if (currentFull.length > 0) {
47396
+ splits.push({
47397
+ literal: bracketed,
47398
+ val: currentFull
47399
+ });
47400
+ }
47401
+
47402
+ current = null;
47403
+ currentFull = "";
47404
+ bracketed = !bracketed;
47405
+ } else if (bracketed) {
47406
+ currentFull += c;
47407
+ } else if (c === current) {
47408
+ currentFull += c;
47409
+ } else {
47410
+ if (currentFull.length > 0) {
47411
+ splits.push({
47412
+ literal: false,
47413
+ val: currentFull
47414
+ });
47415
+ }
47416
+
47417
+ currentFull = c;
47418
+ current = c;
47419
+ }
47369
47420
  }
47370
47421
 
47371
- if (numberingSystem) {
47372
- localeStr += `-nu-${numberingSystem}`;
47422
+ if (currentFull.length > 0) {
47423
+ splits.push({
47424
+ literal: bracketed,
47425
+ val: currentFull
47426
+ });
47373
47427
  }
47374
47428
 
47375
- return localeStr;
47376
- } else {
47377
- return localeStr;
47429
+ return splits;
47378
47430
  }
47379
- }
47380
47431
 
47381
- function mapMonths(f) {
47382
- const ms = [];
47432
+ static macroTokenToFormatOpts(token) {
47433
+ return macroTokenToFormatOpts[token];
47434
+ }
47383
47435
 
47384
- for (let i = 1; i <= 12; i++) {
47385
- const dt = DateTime.utc(2016, i, 1);
47386
- ms.push(f(dt));
47436
+ constructor(locale, formatOpts) {
47437
+ this.opts = formatOpts;
47438
+ this.loc = locale;
47439
+ this.systemLoc = null;
47387
47440
  }
47388
47441
 
47389
- return ms;
47390
- }
47442
+ formatWithSystemDefault(dt, opts) {
47443
+ if (this.systemLoc === null) {
47444
+ this.systemLoc = this.loc.redefaultToSystem();
47445
+ }
47446
+
47447
+ const df = this.systemLoc.dtFormatter(dt, { ...this.opts,
47448
+ ...opts
47449
+ });
47450
+ return df.format();
47451
+ }
47452
+
47453
+ formatDateTime(dt, opts = {}) {
47454
+ const df = this.loc.dtFormatter(dt, { ...this.opts,
47455
+ ...opts
47456
+ });
47457
+ return df.format();
47458
+ }
47459
+
47460
+ formatDateTimeParts(dt, opts = {}) {
47461
+ const df = this.loc.dtFormatter(dt, { ...this.opts,
47462
+ ...opts
47463
+ });
47464
+ return df.formatToParts();
47465
+ }
47466
+
47467
+ resolvedOptions(dt, opts = {}) {
47468
+ const df = this.loc.dtFormatter(dt, { ...this.opts,
47469
+ ...opts
47470
+ });
47471
+ return df.resolvedOptions();
47472
+ }
47473
+
47474
+ num(n, p = 0) {
47475
+ // we get some perf out of doing this here, annoyingly
47476
+ if (this.opts.forceSimple) {
47477
+ return padStart(n, p);
47478
+ }
47479
+
47480
+ const opts = { ...this.opts
47481
+ };
47482
+
47483
+ if (p > 0) {
47484
+ opts.padTo = p;
47485
+ }
47486
+
47487
+ return this.loc.numberFormatter(opts).format(n);
47488
+ }
47489
+
47490
+ formatDateTimeFromString(dt, fmt) {
47491
+ const knownEnglish = this.loc.listingMode() === "en",
47492
+ useDateTimeFormatter = this.loc.outputCalendar && this.loc.outputCalendar !== "gregory",
47493
+ string = (opts, extract) => this.loc.extract(dt, opts, extract),
47494
+ formatOffset = opts => {
47495
+ if (dt.isOffsetFixed && dt.offset === 0 && opts.allowZ) {
47496
+ return "Z";
47497
+ }
47498
+
47499
+ return dt.isValid ? dt.zone.formatOffset(dt.ts, opts.format) : "";
47500
+ },
47501
+ meridiem = () => knownEnglish ? meridiemForDateTime(dt) : string({
47502
+ hour: "numeric",
47503
+ hourCycle: "h12"
47504
+ }, "dayperiod"),
47505
+ month = (length, standalone) => knownEnglish ? monthForDateTime(dt, length) : string(standalone ? {
47506
+ month: length
47507
+ } : {
47508
+ month: length,
47509
+ day: "numeric"
47510
+ }, "month"),
47511
+ weekday = (length, standalone) => knownEnglish ? weekdayForDateTime(dt, length) : string(standalone ? {
47512
+ weekday: length
47513
+ } : {
47514
+ weekday: length,
47515
+ month: "long",
47516
+ day: "numeric"
47517
+ }, "weekday"),
47518
+ maybeMacro = token => {
47519
+ const formatOpts = Formatter.macroTokenToFormatOpts(token);
47520
+
47521
+ if (formatOpts) {
47522
+ return this.formatWithSystemDefault(dt, formatOpts);
47523
+ } else {
47524
+ return token;
47525
+ }
47526
+ },
47527
+ era = length => knownEnglish ? eraForDateTime(dt, length) : string({
47528
+ era: length
47529
+ }, "era"),
47530
+ tokenToString = token => {
47531
+ // Where possible: http://cldr.unicode.org/translation/date-time-1/date-time#TOC-Standalone-vs.-Format-Styles
47532
+ switch (token) {
47533
+ // ms
47534
+ case "S":
47535
+ return this.num(dt.millisecond);
47536
+
47537
+ case "u": // falls through
47538
+
47539
+ case "SSS":
47540
+ return this.num(dt.millisecond, 3);
47541
+ // seconds
47542
+
47543
+ case "s":
47544
+ return this.num(dt.second);
47545
+
47546
+ case "ss":
47547
+ return this.num(dt.second, 2);
47548
+ // fractional seconds
47549
+
47550
+ case "uu":
47551
+ return this.num(Math.floor(dt.millisecond / 10), 2);
47552
+
47553
+ case "uuu":
47554
+ return this.num(Math.floor(dt.millisecond / 100));
47555
+ // minutes
47556
+
47557
+ case "m":
47558
+ return this.num(dt.minute);
47559
+
47560
+ case "mm":
47561
+ return this.num(dt.minute, 2);
47562
+ // hours
47563
+
47564
+ case "h":
47565
+ return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12);
47566
+
47567
+ case "hh":
47568
+ return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12, 2);
47569
+
47570
+ case "H":
47571
+ return this.num(dt.hour);
47572
+
47573
+ case "HH":
47574
+ return this.num(dt.hour, 2);
47575
+ // offset
47576
+
47577
+ case "Z":
47578
+ // like +6
47579
+ return formatOffset({
47580
+ format: "narrow",
47581
+ allowZ: this.opts.allowZ
47582
+ });
47391
47583
 
47392
- function mapWeekdays(f) {
47393
- const ms = [];
47584
+ case "ZZ":
47585
+ // like +06:00
47586
+ return formatOffset({
47587
+ format: "short",
47588
+ allowZ: this.opts.allowZ
47589
+ });
47394
47590
 
47395
- for (let i = 1; i <= 7; i++) {
47396
- const dt = DateTime.utc(2016, 11, 13 + i);
47397
- ms.push(f(dt));
47398
- }
47591
+ case "ZZZ":
47592
+ // like +0600
47593
+ return formatOffset({
47594
+ format: "techie",
47595
+ allowZ: this.opts.allowZ
47596
+ });
47399
47597
 
47400
- return ms;
47401
- }
47598
+ case "ZZZZ":
47599
+ // like EST
47600
+ return dt.zone.offsetName(dt.ts, {
47601
+ format: "short",
47602
+ locale: this.loc.locale
47603
+ });
47402
47604
 
47403
- function listStuff(loc, length, defaultOK, englishFn, intlFn) {
47404
- const mode = loc.listingMode(defaultOK);
47605
+ case "ZZZZZ":
47606
+ // like Eastern Standard Time
47607
+ return dt.zone.offsetName(dt.ts, {
47608
+ format: "long",
47609
+ locale: this.loc.locale
47610
+ });
47611
+ // zone
47405
47612
 
47406
- if (mode === "error") {
47407
- return null;
47408
- } else if (mode === "en") {
47409
- return englishFn(length);
47410
- } else {
47411
- return intlFn(length);
47412
- }
47413
- }
47613
+ case "z":
47614
+ // like America/New_York
47615
+ return dt.zoneName;
47616
+ // meridiems
47414
47617
 
47415
- function supportsFastNumbers(loc) {
47416
- if (loc.numberingSystem && loc.numberingSystem !== "latn") {
47417
- return false;
47418
- } else {
47419
- return loc.numberingSystem === "latn" || !loc.locale || loc.locale.startsWith("en") || new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem === "latn";
47420
- }
47421
- }
47422
- /**
47423
- * @private
47424
- */
47618
+ case "a":
47619
+ return meridiem();
47620
+ // dates
47425
47621
 
47622
+ case "d":
47623
+ return useDateTimeFormatter ? string({
47624
+ day: "numeric"
47625
+ }, "day") : this.num(dt.day);
47426
47626
 
47427
- class PolyNumberFormatter {
47428
- constructor(intl, forceSimple, opts) {
47429
- this.padTo = opts.padTo || 0;
47430
- this.floor = opts.floor || false;
47431
- const {
47432
- padTo,
47433
- floor,
47434
- ...otherOpts
47435
- } = opts;
47627
+ case "dd":
47628
+ return useDateTimeFormatter ? string({
47629
+ day: "2-digit"
47630
+ }, "day") : this.num(dt.day, 2);
47631
+ // weekdays - standalone
47436
47632
 
47437
- if (!forceSimple || Object.keys(otherOpts).length > 0) {
47438
- const intlOpts = {
47439
- useGrouping: false,
47440
- ...opts
47441
- };
47442
- if (opts.padTo > 0) intlOpts.minimumIntegerDigits = opts.padTo;
47443
- this.inf = getCachedINF(intl, intlOpts);
47444
- }
47445
- }
47633
+ case "c":
47634
+ // like 1
47635
+ return this.num(dt.weekday);
47446
47636
 
47447
- format(i) {
47448
- if (this.inf) {
47449
- const fixed = this.floor ? Math.floor(i) : i;
47450
- return this.inf.format(fixed);
47451
- } else {
47452
- // to match the browser's numberformatter defaults
47453
- const fixed = this.floor ? Math.floor(i) : roundTo(i, 3);
47454
- return padStart(fixed, this.padTo);
47455
- }
47456
- }
47637
+ case "ccc":
47638
+ // like 'Tues'
47639
+ return weekday("short", true);
47457
47640
 
47458
- }
47459
- /**
47460
- * @private
47461
- */
47641
+ case "cccc":
47642
+ // like 'Tuesday'
47643
+ return weekday("long", true);
47462
47644
 
47645
+ case "ccccc":
47646
+ // like 'T'
47647
+ return weekday("narrow", true);
47648
+ // weekdays - format
47463
47649
 
47464
- class PolyDateFormatter {
47465
- constructor(dt, intl, opts) {
47466
- this.opts = opts;
47467
- let z;
47650
+ case "E":
47651
+ // like 1
47652
+ return this.num(dt.weekday);
47468
47653
 
47469
- if (dt.zone.isUniversal) {
47470
- // UTC-8 or Etc/UTC-8 are not part of tzdata, only Etc/GMT+8 and the like.
47471
- // That is why fixed-offset TZ is set to that unless it is:
47472
- // 1. Representing offset 0 when UTC is used to maintain previous behavior and does not become GMT.
47473
- // 2. Unsupported by the browser:
47474
- // - some do not support Etc/
47475
- // - < Etc/GMT-14, > Etc/GMT+12, and 30-minute or 45-minute offsets are not part of tzdata
47476
- const gmtOffset = -1 * (dt.offset / 60);
47477
- const offsetZ = gmtOffset >= 0 ? `Etc/GMT+${gmtOffset}` : `Etc/GMT${gmtOffset}`;
47654
+ case "EEE":
47655
+ // like 'Tues'
47656
+ return weekday("short", false);
47478
47657
 
47479
- if (dt.offset !== 0 && IANAZone.create(offsetZ).valid) {
47480
- z = offsetZ;
47481
- this.dt = dt;
47482
- } else {
47483
- // Not all fixed-offset zones like Etc/+4:30 are present in tzdata.
47484
- // So we have to make do. Two cases:
47485
- // 1. The format options tell us to show the zone. We can't do that, so the best
47486
- // we can do is format the date in UTC.
47487
- // 2. The format options don't tell us to show the zone. Then we can adjust them
47488
- // the time and tell the formatter to show it to us in UTC, so that the time is right
47489
- // and the bad zone doesn't show up.
47490
- z = "UTC";
47658
+ case "EEEE":
47659
+ // like 'Tuesday'
47660
+ return weekday("long", false);
47491
47661
 
47492
- if (opts.timeZoneName) {
47493
- this.dt = dt;
47494
- } else {
47495
- this.dt = dt.offset === 0 ? dt : DateTime.fromMillis(dt.ts + dt.offset * 60 * 1000);
47496
- }
47497
- }
47498
- } else if (dt.zone.type === "system") {
47499
- this.dt = dt;
47500
- } else {
47501
- this.dt = dt;
47502
- z = dt.zone.name;
47503
- }
47662
+ case "EEEEE":
47663
+ // like 'T'
47664
+ return weekday("narrow", false);
47665
+ // months - standalone
47504
47666
 
47505
- const intlOpts = { ...this.opts
47506
- };
47667
+ case "L":
47668
+ // like 1
47669
+ return useDateTimeFormatter ? string({
47670
+ month: "numeric",
47671
+ day: "numeric"
47672
+ }, "month") : this.num(dt.month);
47507
47673
 
47508
- if (z) {
47509
- intlOpts.timeZone = z;
47510
- }
47674
+ case "LL":
47675
+ // like 01, doesn't seem to work
47676
+ return useDateTimeFormatter ? string({
47677
+ month: "2-digit",
47678
+ day: "numeric"
47679
+ }, "month") : this.num(dt.month, 2);
47511
47680
 
47512
- this.dtf = getCachedDTF(intl, intlOpts);
47513
- }
47681
+ case "LLL":
47682
+ // like Jan
47683
+ return month("short", true);
47514
47684
 
47515
- format() {
47516
- return this.dtf.format(this.dt.toJSDate());
47517
- }
47685
+ case "LLLL":
47686
+ // like January
47687
+ return month("long", true);
47518
47688
 
47519
- formatToParts() {
47520
- return this.dtf.formatToParts(this.dt.toJSDate());
47521
- }
47689
+ case "LLLLL":
47690
+ // like J
47691
+ return month("narrow", true);
47692
+ // months - format
47522
47693
 
47523
- resolvedOptions() {
47524
- return this.dtf.resolvedOptions();
47525
- }
47694
+ case "M":
47695
+ // like 1
47696
+ return useDateTimeFormatter ? string({
47697
+ month: "numeric"
47698
+ }, "month") : this.num(dt.month);
47526
47699
 
47527
- }
47528
- /**
47529
- * @private
47530
- */
47700
+ case "MM":
47701
+ // like 01
47702
+ return useDateTimeFormatter ? string({
47703
+ month: "2-digit"
47704
+ }, "month") : this.num(dt.month, 2);
47531
47705
 
47706
+ case "MMM":
47707
+ // like Jan
47708
+ return month("short", false);
47532
47709
 
47533
- class PolyRelFormatter {
47534
- constructor(intl, isEnglish, opts) {
47535
- this.opts = {
47536
- style: "long",
47537
- ...opts
47538
- };
47710
+ case "MMMM":
47711
+ // like January
47712
+ return month("long", false);
47539
47713
 
47540
- if (!isEnglish && hasRelative()) {
47541
- this.rtf = getCachedRTF(intl, opts);
47542
- }
47543
- }
47714
+ case "MMMMM":
47715
+ // like J
47716
+ return month("narrow", false);
47717
+ // years
47544
47718
 
47545
- format(count, unit) {
47546
- if (this.rtf) {
47547
- return this.rtf.format(count, unit);
47548
- } else {
47549
- return formatRelativeTime(unit, count, this.opts.numeric, this.opts.style !== "long");
47550
- }
47551
- }
47719
+ case "y":
47720
+ // like 2014
47721
+ return useDateTimeFormatter ? string({
47722
+ year: "numeric"
47723
+ }, "year") : this.num(dt.year);
47552
47724
 
47553
- formatToParts(count, unit) {
47554
- if (this.rtf) {
47555
- return this.rtf.formatToParts(count, unit);
47556
- } else {
47557
- return [];
47558
- }
47559
- }
47725
+ case "yy":
47726
+ // like 14
47727
+ return useDateTimeFormatter ? string({
47728
+ year: "2-digit"
47729
+ }, "year") : this.num(dt.year.toString().slice(-2), 2);
47560
47730
 
47561
- }
47562
- /**
47563
- * @private
47564
- */
47731
+ case "yyyy":
47732
+ // like 0012
47733
+ return useDateTimeFormatter ? string({
47734
+ year: "numeric"
47735
+ }, "year") : this.num(dt.year, 4);
47565
47736
 
47737
+ case "yyyyyy":
47738
+ // like 000012
47739
+ return useDateTimeFormatter ? string({
47740
+ year: "numeric"
47741
+ }, "year") : this.num(dt.year, 6);
47742
+ // eras
47566
47743
 
47567
- class Locale {
47568
- static fromOpts(opts) {
47569
- return Locale.create(opts.locale, opts.numberingSystem, opts.outputCalendar, opts.defaultToEN);
47570
- }
47744
+ case "G":
47745
+ // like AD
47746
+ return era("short");
47571
47747
 
47572
- static create(locale, numberingSystem, outputCalendar, defaultToEN = false) {
47573
- const specifiedLocale = locale || Settings.defaultLocale; // the system locale is useful for human readable strings but annoying for parsing/formatting known formats
47748
+ case "GG":
47749
+ // like Anno Domini
47750
+ return era("long");
47574
47751
 
47575
- const localeR = specifiedLocale || (defaultToEN ? "en-US" : systemLocale());
47576
- const numberingSystemR = numberingSystem || Settings.defaultNumberingSystem;
47577
- const outputCalendarR = outputCalendar || Settings.defaultOutputCalendar;
47578
- return new Locale(localeR, numberingSystemR, outputCalendarR, specifiedLocale);
47579
- }
47752
+ case "GGGGG":
47753
+ return era("narrow");
47580
47754
 
47581
- static resetCache() {
47582
- sysLocaleCache = null;
47583
- intlDTCache = {};
47584
- intlNumCache = {};
47585
- intlRelCache = {};
47586
- }
47755
+ case "kk":
47756
+ return this.num(dt.weekYear.toString().slice(-2), 2);
47587
47757
 
47588
- static fromObject({
47589
- locale,
47590
- numberingSystem,
47591
- outputCalendar
47592
- } = {}) {
47593
- return Locale.create(locale, numberingSystem, outputCalendar);
47594
- }
47758
+ case "kkkk":
47759
+ return this.num(dt.weekYear, 4);
47595
47760
 
47596
- constructor(locale, numbering, outputCalendar, specifiedLocale) {
47597
- const [parsedLocale, parsedNumberingSystem, parsedOutputCalendar] = parseLocaleString(locale);
47598
- this.locale = parsedLocale;
47599
- this.numberingSystem = numbering || parsedNumberingSystem || null;
47600
- this.outputCalendar = outputCalendar || parsedOutputCalendar || null;
47601
- this.intl = intlConfigString(this.locale, this.numberingSystem, this.outputCalendar);
47602
- this.weekdaysCache = {
47603
- format: {},
47604
- standalone: {}
47605
- };
47606
- this.monthsCache = {
47607
- format: {},
47608
- standalone: {}
47609
- };
47610
- this.meridiemCache = null;
47611
- this.eraCache = {};
47612
- this.specifiedLocale = specifiedLocale;
47613
- this.fastNumbersCached = null;
47614
- }
47761
+ case "W":
47762
+ return this.num(dt.weekNumber);
47615
47763
 
47616
- get fastNumbers() {
47617
- if (this.fastNumbersCached == null) {
47618
- this.fastNumbersCached = supportsFastNumbers(this);
47619
- }
47764
+ case "WW":
47765
+ return this.num(dt.weekNumber, 2);
47620
47766
 
47621
- return this.fastNumbersCached;
47622
- }
47767
+ case "o":
47768
+ return this.num(dt.ordinal);
47623
47769
 
47624
- listingMode() {
47625
- const isActuallyEn = this.isEnglish();
47626
- const hasNoWeirdness = (this.numberingSystem === null || this.numberingSystem === "latn") && (this.outputCalendar === null || this.outputCalendar === "gregory");
47627
- return isActuallyEn && hasNoWeirdness ? "en" : "intl";
47628
- }
47770
+ case "ooo":
47771
+ return this.num(dt.ordinal, 3);
47629
47772
 
47630
- clone(alts) {
47631
- if (!alts || Object.getOwnPropertyNames(alts).length === 0) {
47632
- return this;
47633
- } else {
47634
- return Locale.create(alts.locale || this.specifiedLocale, alts.numberingSystem || this.numberingSystem, alts.outputCalendar || this.outputCalendar, alts.defaultToEN || false);
47635
- }
47636
- }
47773
+ case "q":
47774
+ // like 1
47775
+ return this.num(dt.quarter);
47637
47776
 
47638
- redefaultToEN(alts = {}) {
47639
- return this.clone({ ...alts,
47640
- defaultToEN: true
47641
- });
47642
- }
47777
+ case "qq":
47778
+ // like 01
47779
+ return this.num(dt.quarter, 2);
47643
47780
 
47644
- redefaultToSystem(alts = {}) {
47645
- return this.clone({ ...alts,
47646
- defaultToEN: false
47647
- });
47648
- }
47781
+ case "X":
47782
+ return this.num(Math.floor(dt.ts / 1000));
47649
47783
 
47650
- months(length, format = false, defaultOK = true) {
47651
- return listStuff(this, length, defaultOK, months, () => {
47652
- const intl = format ? {
47653
- month: length,
47654
- day: "numeric"
47655
- } : {
47656
- month: length
47657
- },
47658
- formatStr = format ? "format" : "standalone";
47784
+ case "x":
47785
+ return this.num(dt.ts);
47659
47786
 
47660
- if (!this.monthsCache[formatStr][length]) {
47661
- this.monthsCache[formatStr][length] = mapMonths(dt => this.extract(dt, intl, "month"));
47787
+ default:
47788
+ return maybeMacro(token);
47662
47789
  }
47790
+ };
47663
47791
 
47664
- return this.monthsCache[formatStr][length];
47665
- });
47792
+ return stringifyTokens(Formatter.parseFormat(fmt), tokenToString);
47666
47793
  }
47667
47794
 
47668
- weekdays(length, format = false, defaultOK = true) {
47669
- return listStuff(this, length, defaultOK, weekdays, () => {
47670
- const intl = format ? {
47671
- weekday: length,
47672
- year: "numeric",
47673
- month: "long",
47674
- day: "numeric"
47675
- } : {
47676
- weekday: length
47677
- },
47678
- formatStr = format ? "format" : "standalone";
47679
-
47680
- if (!this.weekdaysCache[formatStr][length]) {
47681
- this.weekdaysCache[formatStr][length] = mapWeekdays(dt => this.extract(dt, intl, "weekday"));
47682
- }
47795
+ formatDurationFromString(dur, fmt) {
47796
+ const tokenToField = token => {
47797
+ switch (token[0]) {
47798
+ case "S":
47799
+ return "millisecond";
47683
47800
 
47684
- return this.weekdaysCache[formatStr][length];
47685
- });
47686
- }
47801
+ case "s":
47802
+ return "second";
47687
47803
 
47688
- meridiems(defaultOK = true) {
47689
- return listStuff(this, undefined, defaultOK, () => meridiems, () => {
47690
- // In theory there could be aribitrary day periods. We're gonna assume there are exactly two
47691
- // for AM and PM. This is probably wrong, but it's makes parsing way easier.
47692
- if (!this.meridiemCache) {
47693
- const intl = {
47694
- hour: "numeric",
47695
- hourCycle: "h12"
47696
- };
47697
- this.meridiemCache = [DateTime.utc(2016, 11, 13, 9), DateTime.utc(2016, 11, 13, 19)].map(dt => this.extract(dt, intl, "dayperiod"));
47698
- }
47804
+ case "m":
47805
+ return "minute";
47699
47806
 
47700
- return this.meridiemCache;
47701
- });
47702
- }
47807
+ case "h":
47808
+ return "hour";
47703
47809
 
47704
- eras(length, defaultOK = true) {
47705
- return listStuff(this, length, defaultOK, eras, () => {
47706
- const intl = {
47707
- era: length
47708
- }; // This is problematic. Different calendars are going to define eras totally differently. What I need is the minimum set of dates
47709
- // to definitely enumerate them.
47810
+ case "d":
47811
+ return "day";
47710
47812
 
47711
- if (!this.eraCache[length]) {
47712
- this.eraCache[length] = [DateTime.utc(-40, 1, 1), DateTime.utc(2017, 1, 1)].map(dt => this.extract(dt, intl, "era"));
47713
- }
47813
+ case "w":
47814
+ return "week";
47714
47815
 
47715
- return this.eraCache[length];
47716
- });
47717
- }
47816
+ case "M":
47817
+ return "month";
47718
47818
 
47719
- extract(dt, intlOpts, field) {
47720
- const df = this.dtFormatter(dt, intlOpts),
47721
- results = df.formatToParts(),
47722
- matching = results.find(m => m.type.toLowerCase() === field);
47723
- return matching ? matching.value : null;
47724
- }
47819
+ case "y":
47820
+ return "year";
47725
47821
 
47726
- numberFormatter(opts = {}) {
47727
- // this forcesimple option is never used (the only caller short-circuits on it, but it seems safer to leave)
47728
- // (in contrast, the rest of the condition is used heavily)
47729
- return new PolyNumberFormatter(this.intl, opts.forceSimple || this.fastNumbers, opts);
47730
- }
47822
+ default:
47823
+ return null;
47824
+ }
47825
+ },
47826
+ tokenToString = lildur => token => {
47827
+ const mapped = tokenToField(token);
47731
47828
 
47732
- dtFormatter(dt, intlOpts = {}) {
47733
- return new PolyDateFormatter(dt, this.intl, intlOpts);
47734
- }
47829
+ if (mapped) {
47830
+ return this.num(lildur.get(mapped), token.length);
47831
+ } else {
47832
+ return token;
47833
+ }
47834
+ },
47835
+ tokens = Formatter.parseFormat(fmt),
47836
+ realTokens = tokens.reduce((found, {
47837
+ literal,
47838
+ val
47839
+ }) => literal ? found : found.concat(val), []),
47840
+ collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter(t => t));
47735
47841
 
47736
- relFormatter(opts = {}) {
47737
- return new PolyRelFormatter(this.intl, this.isEnglish(), opts);
47842
+ return stringifyTokens(tokens, tokenToString(collapsed));
47738
47843
  }
47739
47844
 
47740
- listFormatter(opts = {}) {
47741
- return getCachedLF(this.intl, opts);
47742
- }
47845
+ }
47743
47846
 
47744
- isEnglish() {
47745
- return this.locale === "en" || this.locale.toLowerCase() === "en-us" || new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us");
47847
+ class Invalid {
47848
+ constructor(reason, explanation) {
47849
+ this.reason = reason;
47850
+ this.explanation = explanation;
47746
47851
  }
47747
47852
 
47748
- equals(other) {
47749
- return this.locale === other.locale && this.numberingSystem === other.numberingSystem && this.outputCalendar === other.outputCalendar;
47853
+ toMessage() {
47854
+ if (this.explanation) {
47855
+ return `${this.reason}: ${this.explanation}`;
47856
+ } else {
47857
+ return this.reason;
47858
+ }
47750
47859
  }
47751
47860
 
47752
47861
  }
@@ -47761,6 +47870,8 @@ class Locale {
47761
47870
  * Some extractions are super dumb and simpleParse and fromStrings help DRY them.
47762
47871
  */
47763
47872
 
47873
+ const ianaRegex = /[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;
47874
+
47764
47875
  function combineRegexes(...regexes) {
47765
47876
  const full = regexes.reduce((f, r) => f + r.source, "");
47766
47877
  return RegExp(`^${full}$`);
@@ -53026,7 +53137,7 @@ function friendlyDateTime(dateTimeish) {
53026
53137
  }
53027
53138
  }
53028
53139
 
53029
- const VERSION = "3.1.0";
53140
+ const VERSION = "3.1.1";
53030
53141
 
53031
53142
  exports.DateTime = DateTime;
53032
53143
  exports.Duration = Duration;