@fedify/vocab-runtime 2.0.35 → 2.0.36-dev.2551
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deno.json +1 -1
- package/dist/mod.cjs +1 -1
- package/dist/mod.js +1 -1
- package/dist/temporal.cjs +19 -1
- package/dist/temporal.d.cts +13 -2
- package/dist/temporal.d.ts +13 -2
- package/dist/temporal.js +19 -2
- package/dist/tests/{body-Cul4-oB8.cjs → body-5wwZdMK0.cjs} +1 -1
- package/dist/tests/{body-ByUnLtuw.mjs → body-DqkK9XBY.mjs} +1 -1
- package/dist/tests/body.test.cjs +1 -1
- package/dist/tests/body.test.mjs +1 -1
- package/dist/tests/docloader.test.cjs +2 -2
- package/dist/tests/docloader.test.mjs +2 -2
- package/dist/tests/{request-B7Iyskql.cjs → request-BNAT7gZ3.cjs} +1 -1
- package/dist/tests/{request-pGToUa6Q.mjs → request-BiuryHCs.mjs} +1 -1
- package/dist/tests/request.test.cjs +1 -1
- package/dist/tests/request.test.mjs +1 -1
- package/dist/tests/temporal.test.cjs +85 -1
- package/dist/tests/temporal.test.mjs +85 -1
- package/package.json +1 -1
- package/src/temporal.test.ts +91 -1
- package/src/temporal.ts +20 -1
package/deno.json
CHANGED
package/dist/mod.cjs
CHANGED
|
@@ -4502,7 +4502,7 @@ const preloadedContexts = {
|
|
|
4502
4502
|
//#endregion
|
|
4503
4503
|
//#region deno.json
|
|
4504
4504
|
var name = "@fedify/vocab-runtime";
|
|
4505
|
-
var version = "2.0.
|
|
4505
|
+
var version = "2.0.36-dev.2551+8b012df4";
|
|
4506
4506
|
//#endregion
|
|
4507
4507
|
//#region src/request.ts
|
|
4508
4508
|
/**
|
package/dist/mod.js
CHANGED
|
@@ -4498,7 +4498,7 @@ const preloadedContexts = {
|
|
|
4498
4498
|
//#endregion
|
|
4499
4499
|
//#region deno.json
|
|
4500
4500
|
var name = "@fedify/vocab-runtime";
|
|
4501
|
-
var version = "2.0.
|
|
4501
|
+
var version = "2.0.36-dev.2551+8b012df4";
|
|
4502
4502
|
//#endregion
|
|
4503
4503
|
//#region src/request.ts
|
|
4504
4504
|
/**
|
package/dist/temporal.cjs
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
//#region src/temporal.ts
|
|
4
4
|
/**
|
|
5
|
-
* Type guards for `Temporal` namespace objects
|
|
5
|
+
* Type guards for `Temporal` namespace objects and normalization of
|
|
6
|
+
* `xsd:dateTime` literals.
|
|
6
7
|
*
|
|
7
8
|
* Fedify accepts both runtime polyfills (e.g. `@js-temporal/polyfill`,
|
|
8
9
|
* `temporal-polyfill`) and the host's native `Temporal` implementation
|
|
@@ -55,6 +56,23 @@ function isTemporalInstant(value) {
|
|
|
55
56
|
function isTemporalDuration(value) {
|
|
56
57
|
return typeof value === "object" && value !== null && Object.prototype.toString.call(value) === "[object Temporal.Duration]" && "sign" in value && (value.sign === -1 || value.sign === 0 || value.sign === 1) && "toString" in value && typeof value.toString === "function" && value.toString !== Object.prototype.toString;
|
|
57
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Normalizes an `xsd:dateTime` literal into a form that
|
|
61
|
+
* `Temporal.Instant.from()` accepts. A literal without a UTC offset is
|
|
62
|
+
* treated as UTC, and seconds omitted before a fraction, which Activity Streams
|
|
63
|
+
* 2.0 allows, are filled in.
|
|
64
|
+
*
|
|
65
|
+
* @param value The date-time literal to normalize.
|
|
66
|
+
* @returns The normalized literal.
|
|
67
|
+
*/
|
|
68
|
+
function normalizeDateTimeLiteral(value) {
|
|
69
|
+
const timeStart = value.search(/[Tt ]/) + 1;
|
|
70
|
+
if (timeStart < 1) return value;
|
|
71
|
+
const date = value.substring(0, timeStart);
|
|
72
|
+
const time = value.substring(timeStart).replace(/^(\d{2}:\d{2})(?=\.)/, "$1:00");
|
|
73
|
+
return date + (/[Zz+-]/.test(time) ? time : time + "Z");
|
|
74
|
+
}
|
|
58
75
|
//#endregion
|
|
59
76
|
exports.isTemporalDuration = isTemporalDuration;
|
|
60
77
|
exports.isTemporalInstant = isTemporalInstant;
|
|
78
|
+
exports.normalizeDateTimeLiteral = normalizeDateTimeLiteral;
|
package/dist/temporal.d.cts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
2
|
//#region src/temporal.d.ts
|
|
3
3
|
/**
|
|
4
|
-
* Type guards for `Temporal` namespace objects
|
|
4
|
+
* Type guards for `Temporal` namespace objects and normalization of
|
|
5
|
+
* `xsd:dateTime` literals.
|
|
5
6
|
*
|
|
6
7
|
* Fedify accepts both runtime polyfills (e.g. `@js-temporal/polyfill`,
|
|
7
8
|
* `temporal-polyfill`) and the host's native `Temporal` implementation
|
|
@@ -50,5 +51,15 @@ declare function isTemporalInstant(value: unknown): value is Temporal.Instant;
|
|
|
50
51
|
* and overrides `toString`; `false` otherwise.
|
|
51
52
|
*/
|
|
52
53
|
declare function isTemporalDuration(value: unknown): value is Temporal.Duration;
|
|
54
|
+
/**
|
|
55
|
+
* Normalizes an `xsd:dateTime` literal into a form that
|
|
56
|
+
* `Temporal.Instant.from()` accepts. A literal without a UTC offset is
|
|
57
|
+
* treated as UTC, and seconds omitted before a fraction, which Activity Streams
|
|
58
|
+
* 2.0 allows, are filled in.
|
|
59
|
+
*
|
|
60
|
+
* @param value The date-time literal to normalize.
|
|
61
|
+
* @returns The normalized literal.
|
|
62
|
+
*/
|
|
63
|
+
declare function normalizeDateTimeLiteral(value: string): string;
|
|
53
64
|
//#endregion
|
|
54
|
-
export { isTemporalDuration, isTemporalInstant };
|
|
65
|
+
export { isTemporalDuration, isTemporalInstant, normalizeDateTimeLiteral };
|
package/dist/temporal.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
2
|
//#region src/temporal.d.ts
|
|
3
3
|
/**
|
|
4
|
-
* Type guards for `Temporal` namespace objects
|
|
4
|
+
* Type guards for `Temporal` namespace objects and normalization of
|
|
5
|
+
* `xsd:dateTime` literals.
|
|
5
6
|
*
|
|
6
7
|
* Fedify accepts both runtime polyfills (e.g. `@js-temporal/polyfill`,
|
|
7
8
|
* `temporal-polyfill`) and the host's native `Temporal` implementation
|
|
@@ -50,5 +51,15 @@ declare function isTemporalInstant(value: unknown): value is Temporal.Instant;
|
|
|
50
51
|
* and overrides `toString`; `false` otherwise.
|
|
51
52
|
*/
|
|
52
53
|
declare function isTemporalDuration(value: unknown): value is Temporal.Duration;
|
|
54
|
+
/**
|
|
55
|
+
* Normalizes an `xsd:dateTime` literal into a form that
|
|
56
|
+
* `Temporal.Instant.from()` accepts. A literal without a UTC offset is
|
|
57
|
+
* treated as UTC, and seconds omitted before a fraction, which Activity Streams
|
|
58
|
+
* 2.0 allows, are filled in.
|
|
59
|
+
*
|
|
60
|
+
* @param value The date-time literal to normalize.
|
|
61
|
+
* @returns The normalized literal.
|
|
62
|
+
*/
|
|
63
|
+
declare function normalizeDateTimeLiteral(value: string): string;
|
|
53
64
|
//#endregion
|
|
54
|
-
export { isTemporalDuration, isTemporalInstant };
|
|
65
|
+
export { isTemporalDuration, isTemporalInstant, normalizeDateTimeLiteral };
|
package/dist/temporal.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
//#region src/temporal.ts
|
|
3
3
|
/**
|
|
4
|
-
* Type guards for `Temporal` namespace objects
|
|
4
|
+
* Type guards for `Temporal` namespace objects and normalization of
|
|
5
|
+
* `xsd:dateTime` literals.
|
|
5
6
|
*
|
|
6
7
|
* Fedify accepts both runtime polyfills (e.g. `@js-temporal/polyfill`,
|
|
7
8
|
* `temporal-polyfill`) and the host's native `Temporal` implementation
|
|
@@ -54,5 +55,21 @@ function isTemporalInstant(value) {
|
|
|
54
55
|
function isTemporalDuration(value) {
|
|
55
56
|
return typeof value === "object" && value !== null && Object.prototype.toString.call(value) === "[object Temporal.Duration]" && "sign" in value && (value.sign === -1 || value.sign === 0 || value.sign === 1) && "toString" in value && typeof value.toString === "function" && value.toString !== Object.prototype.toString;
|
|
56
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Normalizes an `xsd:dateTime` literal into a form that
|
|
60
|
+
* `Temporal.Instant.from()` accepts. A literal without a UTC offset is
|
|
61
|
+
* treated as UTC, and seconds omitted before a fraction, which Activity Streams
|
|
62
|
+
* 2.0 allows, are filled in.
|
|
63
|
+
*
|
|
64
|
+
* @param value The date-time literal to normalize.
|
|
65
|
+
* @returns The normalized literal.
|
|
66
|
+
*/
|
|
67
|
+
function normalizeDateTimeLiteral(value) {
|
|
68
|
+
const timeStart = value.search(/[Tt ]/) + 1;
|
|
69
|
+
if (timeStart < 1) return value;
|
|
70
|
+
const date = value.substring(0, timeStart);
|
|
71
|
+
const time = value.substring(timeStart).replace(/^(\d{2}:\d{2})(?=\.)/, "$1:00");
|
|
72
|
+
return date + (/[Zz+-]/.test(time) ? time : time + "Z");
|
|
73
|
+
}
|
|
57
74
|
//#endregion
|
|
58
|
-
export { isTemporalDuration, isTemporalInstant };
|
|
75
|
+
export { isTemporalDuration, isTemporalInstant, normalizeDateTimeLiteral };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require("./chunk-Do9eywBl.cjs");
|
|
2
|
-
const require_request = require("./request-
|
|
2
|
+
const require_request = require("./request-BNAT7gZ3.cjs");
|
|
3
3
|
let _logtape_logtape = require("@logtape/logtape");
|
|
4
4
|
//#region src/body.ts
|
|
5
5
|
/** Decoded JSON body limit: 16 MiB. @internal */
|
package/dist/tests/body.test.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require("./chunk-Do9eywBl.cjs");
|
|
2
|
-
const require_body = require("./body-
|
|
2
|
+
const require_body = require("./body-5wwZdMK0.cjs");
|
|
3
3
|
let node_assert_strict = require("node:assert/strict");
|
|
4
4
|
let node_test = require("node:test");
|
|
5
5
|
let node_zlib = require("node:zlib");
|
package/dist/tests/body.test.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as readBoundedText, t as BodyTooLargeError } from "./body-
|
|
1
|
+
import { r as readBoundedText, t as BodyTooLargeError } from "./body-DqkK9XBY.mjs";
|
|
2
2
|
import { deepStrictEqual, ok, rejects } from "node:assert/strict";
|
|
3
3
|
import { test } from "node:test";
|
|
4
4
|
import { gunzipSync, gzipSync } from "node:zlib";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Do9eywBl.cjs");
|
|
2
|
-
const require_request = require("./request-
|
|
3
|
-
const require_body = require("./body-
|
|
2
|
+
const require_request = require("./request-BNAT7gZ3.cjs");
|
|
3
|
+
const require_body = require("./body-5wwZdMK0.cjs");
|
|
4
4
|
const require_esm = require("./esm-4DuocLvD.cjs");
|
|
5
5
|
const require_link = require("./link-qDTmjPw_.cjs");
|
|
6
6
|
const require_url = require("./url-DLuSj57U.cjs");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as esm_default } from "./esm-CnLt0wAF.mjs";
|
|
2
|
-
import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-
|
|
3
|
-
import { n as MAX_BODY_SIZE, r as readBoundedText } from "./body-
|
|
2
|
+
import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-BiuryHCs.mjs";
|
|
3
|
+
import { n as MAX_BODY_SIZE, r as readBoundedText } from "./body-DqkK9XBY.mjs";
|
|
4
4
|
import { t as HttpHeaderLink } from "./link-CYszIegt.mjs";
|
|
5
5
|
import { t as UrlError } from "./url-DjsVF44Q.mjs";
|
|
6
6
|
import { n as openDirectFetch, r as openPublicFetch, t as createPublicFetch } from "./public-fetch-BUSPlh1C.mjs";
|
|
@@ -3,7 +3,7 @@ let node_process = require("node:process");
|
|
|
3
3
|
node_process = require_chunk.__toESM(node_process);
|
|
4
4
|
//#region deno.json
|
|
5
5
|
var name = "@fedify/vocab-runtime";
|
|
6
|
-
var version = "2.0.
|
|
6
|
+
var version = "2.0.36-dev.2551+8b012df4";
|
|
7
7
|
//#endregion
|
|
8
8
|
//#region src/request.ts
|
|
9
9
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Do9eywBl.cjs");
|
|
2
|
-
const require_request = require("./request-
|
|
2
|
+
const require_request = require("./request-BNAT7gZ3.cjs");
|
|
3
3
|
let node_test = require("node:test");
|
|
4
4
|
let node_process = require("node:process");
|
|
5
5
|
node_process = require_chunk.__toESM(node_process);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as version, r as getUserAgent } from "./request-
|
|
1
|
+
import { o as version, r as getUserAgent } from "./request-BiuryHCs.mjs";
|
|
2
2
|
import { test } from "node:test";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
import { deepStrictEqual } from "node:assert";
|
|
@@ -4,7 +4,8 @@ let node_assert = require("node:assert");
|
|
|
4
4
|
let _js_temporal_polyfill = require("@js-temporal/polyfill");
|
|
5
5
|
//#region src/temporal.ts
|
|
6
6
|
/**
|
|
7
|
-
* Type guards for `Temporal` namespace objects
|
|
7
|
+
* Type guards for `Temporal` namespace objects and normalization of
|
|
8
|
+
* `xsd:dateTime` literals.
|
|
8
9
|
*
|
|
9
10
|
* Fedify accepts both runtime polyfills (e.g. `@js-temporal/polyfill`,
|
|
10
11
|
* `temporal-polyfill`) and the host's native `Temporal` implementation
|
|
@@ -57,6 +58,22 @@ function isTemporalInstant(value) {
|
|
|
57
58
|
function isTemporalDuration(value) {
|
|
58
59
|
return typeof value === "object" && value !== null && Object.prototype.toString.call(value) === "[object Temporal.Duration]" && "sign" in value && (value.sign === -1 || value.sign === 0 || value.sign === 1) && "toString" in value && typeof value.toString === "function" && value.toString !== Object.prototype.toString;
|
|
59
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Normalizes an `xsd:dateTime` literal into a form that
|
|
63
|
+
* `Temporal.Instant.from()` accepts. A literal without a UTC offset is
|
|
64
|
+
* treated as UTC, and seconds omitted before a fraction, which Activity Streams
|
|
65
|
+
* 2.0 allows, are filled in.
|
|
66
|
+
*
|
|
67
|
+
* @param value The date-time literal to normalize.
|
|
68
|
+
* @returns The normalized literal.
|
|
69
|
+
*/
|
|
70
|
+
function normalizeDateTimeLiteral(value) {
|
|
71
|
+
const timeStart = value.search(/[Tt ]/) + 1;
|
|
72
|
+
if (timeStart < 1) return value;
|
|
73
|
+
const date = value.substring(0, timeStart);
|
|
74
|
+
const time = value.substring(timeStart).replace(/^(\d{2}:\d{2})(?=\.)/, "$1:00");
|
|
75
|
+
return date + (/[Zz+-]/.test(time) ? time : time + "Z");
|
|
76
|
+
}
|
|
60
77
|
//#endregion
|
|
61
78
|
//#region src/temporal.test.ts
|
|
62
79
|
(0, node_test.test)("isTemporalInstant() accepts polyfill instances", () => {
|
|
@@ -131,4 +148,71 @@ function isTemporalDuration(value) {
|
|
|
131
148
|
sign: 0
|
|
132
149
|
}), false);
|
|
133
150
|
});
|
|
151
|
+
const literalsWithOffset = [
|
|
152
|
+
"2024-01-01T10:00Z",
|
|
153
|
+
"2024-01-01T10:00+09:00",
|
|
154
|
+
"2024-01-01T10:00-05:00",
|
|
155
|
+
"2024-01-01T10:00:00Z",
|
|
156
|
+
"2024-01-01T10:00:00+09:00",
|
|
157
|
+
"2024-01-01T10:00:00-05:00",
|
|
158
|
+
"2024-01-01T10:00:00+0900",
|
|
159
|
+
"2024-01-01T10:00:00.123456789Z",
|
|
160
|
+
"2024-01-01t10:00z",
|
|
161
|
+
"2024-01-01 10:00:00Z"
|
|
162
|
+
];
|
|
163
|
+
const literalsWithoutOffset = [
|
|
164
|
+
"2024-01-01T10:00",
|
|
165
|
+
"2024-01-01T10:00:00",
|
|
166
|
+
"2024-01-01T10:00:00.123",
|
|
167
|
+
"2025-01-01 12:34:56"
|
|
168
|
+
];
|
|
169
|
+
const literalsWithoutSeconds = [
|
|
170
|
+
["2024-01-01T10:00.5Z", "2024-01-01T10:00:00.5Z"],
|
|
171
|
+
["2024-01-01T10:00.5+09:00", "2024-01-01T10:00:00.5+09:00"],
|
|
172
|
+
["2024-01-01T10:00.5-05:00", "2024-01-01T10:00:00.5-05:00"],
|
|
173
|
+
["2024-01-01T10:00.5", "2024-01-01T10:00:00.5Z"],
|
|
174
|
+
["2024-01-01T10:00.123456789Z", "2024-01-01T10:00:00.123456789Z"]
|
|
175
|
+
];
|
|
176
|
+
const literalsWithExpandedYear = [["+002024-01-01T10:00", "+002024-01-01T10:00Z"], ["-000001-01-01T10:00.5Z", "-000001-01-01T10:00:00.5Z"]];
|
|
177
|
+
(0, node_test.test)("normalizeDateTimeLiteral() keeps literals with a UTC offset", () => {
|
|
178
|
+
for (const literal of literalsWithOffset) {
|
|
179
|
+
(0, node_assert.strictEqual)(normalizeDateTimeLiteral(literal), literal);
|
|
180
|
+
(0, node_assert.strictEqual)(typeof _js_temporal_polyfill.Temporal.Instant.from(literal), "object");
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
(0, node_test.test)("normalizeDateTimeLiteral() treats literals without an offset as UTC", () => {
|
|
184
|
+
for (const literal of literalsWithoutOffset) {
|
|
185
|
+
(0, node_assert.strictEqual)(normalizeDateTimeLiteral(literal), `${literal}Z`);
|
|
186
|
+
(0, node_assert.strictEqual)(typeof _js_temporal_polyfill.Temporal.Instant.from(normalizeDateTimeLiteral(literal)), "object");
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
(0, node_test.test)("normalizeDateTimeLiteral() keeps literals without a time part", () => {
|
|
190
|
+
(0, node_assert.strictEqual)(normalizeDateTimeLiteral("2024-01-01"), "2024-01-01");
|
|
191
|
+
});
|
|
192
|
+
(0, node_test.test)("normalizeDateTimeLiteral() inserts omitted seconds before a fraction", () => {
|
|
193
|
+
for (const [literal, normalized] of literalsWithoutSeconds) {
|
|
194
|
+
(0, node_assert.strictEqual)(normalizeDateTimeLiteral(literal), normalized);
|
|
195
|
+
(0, node_assert.strictEqual)(typeof _js_temporal_polyfill.Temporal.Instant.from(normalized), "object");
|
|
196
|
+
}
|
|
197
|
+
(0, node_assert.strictEqual)(normalizeDateTimeLiteral("2024-01-01T10:00:00.5Z"), "2024-01-01T10:00:00.5Z");
|
|
198
|
+
});
|
|
199
|
+
(0, node_test.test)("normalizeDateTimeLiteral() handles expanded years", () => {
|
|
200
|
+
for (const [literal, normalized] of literalsWithExpandedYear) {
|
|
201
|
+
(0, node_assert.strictEqual)(normalizeDateTimeLiteral(literal), normalized);
|
|
202
|
+
(0, node_assert.strictEqual)(typeof _js_temporal_polyfill.Temporal.Instant.from(normalized), "object");
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
(0, node_test.test)("normalizeDateTimeLiteral() is idempotent", () => {
|
|
206
|
+
const literals = [
|
|
207
|
+
...literalsWithOffset,
|
|
208
|
+
...literalsWithoutOffset,
|
|
209
|
+
...literalsWithoutSeconds.map(([literal]) => literal),
|
|
210
|
+
...literalsWithExpandedYear.map(([literal]) => literal),
|
|
211
|
+
"2024-01-01"
|
|
212
|
+
];
|
|
213
|
+
for (const literal of literals) {
|
|
214
|
+
const normalized = normalizeDateTimeLiteral(literal);
|
|
215
|
+
(0, node_assert.strictEqual)(normalizeDateTimeLiteral(normalized), normalized);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
134
218
|
//#endregion
|
|
@@ -3,7 +3,8 @@ import { strictEqual } from "node:assert";
|
|
|
3
3
|
import { Temporal } from "@js-temporal/polyfill";
|
|
4
4
|
//#region src/temporal.ts
|
|
5
5
|
/**
|
|
6
|
-
* Type guards for `Temporal` namespace objects
|
|
6
|
+
* Type guards for `Temporal` namespace objects and normalization of
|
|
7
|
+
* `xsd:dateTime` literals.
|
|
7
8
|
*
|
|
8
9
|
* Fedify accepts both runtime polyfills (e.g. `@js-temporal/polyfill`,
|
|
9
10
|
* `temporal-polyfill`) and the host's native `Temporal` implementation
|
|
@@ -56,6 +57,22 @@ function isTemporalInstant(value) {
|
|
|
56
57
|
function isTemporalDuration(value) {
|
|
57
58
|
return typeof value === "object" && value !== null && Object.prototype.toString.call(value) === "[object Temporal.Duration]" && "sign" in value && (value.sign === -1 || value.sign === 0 || value.sign === 1) && "toString" in value && typeof value.toString === "function" && value.toString !== Object.prototype.toString;
|
|
58
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Normalizes an `xsd:dateTime` literal into a form that
|
|
62
|
+
* `Temporal.Instant.from()` accepts. A literal without a UTC offset is
|
|
63
|
+
* treated as UTC, and seconds omitted before a fraction, which Activity Streams
|
|
64
|
+
* 2.0 allows, are filled in.
|
|
65
|
+
*
|
|
66
|
+
* @param value The date-time literal to normalize.
|
|
67
|
+
* @returns The normalized literal.
|
|
68
|
+
*/
|
|
69
|
+
function normalizeDateTimeLiteral(value) {
|
|
70
|
+
const timeStart = value.search(/[Tt ]/) + 1;
|
|
71
|
+
if (timeStart < 1) return value;
|
|
72
|
+
const date = value.substring(0, timeStart);
|
|
73
|
+
const time = value.substring(timeStart).replace(/^(\d{2}:\d{2})(?=\.)/, "$1:00");
|
|
74
|
+
return date + (/[Zz+-]/.test(time) ? time : time + "Z");
|
|
75
|
+
}
|
|
59
76
|
//#endregion
|
|
60
77
|
//#region src/temporal.test.ts
|
|
61
78
|
test("isTemporalInstant() accepts polyfill instances", () => {
|
|
@@ -130,5 +147,72 @@ test("isTemporalDuration() rejects default Object.prototype.toString", () => {
|
|
|
130
147
|
sign: 0
|
|
131
148
|
}), false);
|
|
132
149
|
});
|
|
150
|
+
const literalsWithOffset = [
|
|
151
|
+
"2024-01-01T10:00Z",
|
|
152
|
+
"2024-01-01T10:00+09:00",
|
|
153
|
+
"2024-01-01T10:00-05:00",
|
|
154
|
+
"2024-01-01T10:00:00Z",
|
|
155
|
+
"2024-01-01T10:00:00+09:00",
|
|
156
|
+
"2024-01-01T10:00:00-05:00",
|
|
157
|
+
"2024-01-01T10:00:00+0900",
|
|
158
|
+
"2024-01-01T10:00:00.123456789Z",
|
|
159
|
+
"2024-01-01t10:00z",
|
|
160
|
+
"2024-01-01 10:00:00Z"
|
|
161
|
+
];
|
|
162
|
+
const literalsWithoutOffset = [
|
|
163
|
+
"2024-01-01T10:00",
|
|
164
|
+
"2024-01-01T10:00:00",
|
|
165
|
+
"2024-01-01T10:00:00.123",
|
|
166
|
+
"2025-01-01 12:34:56"
|
|
167
|
+
];
|
|
168
|
+
const literalsWithoutSeconds = [
|
|
169
|
+
["2024-01-01T10:00.5Z", "2024-01-01T10:00:00.5Z"],
|
|
170
|
+
["2024-01-01T10:00.5+09:00", "2024-01-01T10:00:00.5+09:00"],
|
|
171
|
+
["2024-01-01T10:00.5-05:00", "2024-01-01T10:00:00.5-05:00"],
|
|
172
|
+
["2024-01-01T10:00.5", "2024-01-01T10:00:00.5Z"],
|
|
173
|
+
["2024-01-01T10:00.123456789Z", "2024-01-01T10:00:00.123456789Z"]
|
|
174
|
+
];
|
|
175
|
+
const literalsWithExpandedYear = [["+002024-01-01T10:00", "+002024-01-01T10:00Z"], ["-000001-01-01T10:00.5Z", "-000001-01-01T10:00:00.5Z"]];
|
|
176
|
+
test("normalizeDateTimeLiteral() keeps literals with a UTC offset", () => {
|
|
177
|
+
for (const literal of literalsWithOffset) {
|
|
178
|
+
strictEqual(normalizeDateTimeLiteral(literal), literal);
|
|
179
|
+
strictEqual(typeof Temporal.Instant.from(literal), "object");
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
test("normalizeDateTimeLiteral() treats literals without an offset as UTC", () => {
|
|
183
|
+
for (const literal of literalsWithoutOffset) {
|
|
184
|
+
strictEqual(normalizeDateTimeLiteral(literal), `${literal}Z`);
|
|
185
|
+
strictEqual(typeof Temporal.Instant.from(normalizeDateTimeLiteral(literal)), "object");
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
test("normalizeDateTimeLiteral() keeps literals without a time part", () => {
|
|
189
|
+
strictEqual(normalizeDateTimeLiteral("2024-01-01"), "2024-01-01");
|
|
190
|
+
});
|
|
191
|
+
test("normalizeDateTimeLiteral() inserts omitted seconds before a fraction", () => {
|
|
192
|
+
for (const [literal, normalized] of literalsWithoutSeconds) {
|
|
193
|
+
strictEqual(normalizeDateTimeLiteral(literal), normalized);
|
|
194
|
+
strictEqual(typeof Temporal.Instant.from(normalized), "object");
|
|
195
|
+
}
|
|
196
|
+
strictEqual(normalizeDateTimeLiteral("2024-01-01T10:00:00.5Z"), "2024-01-01T10:00:00.5Z");
|
|
197
|
+
});
|
|
198
|
+
test("normalizeDateTimeLiteral() handles expanded years", () => {
|
|
199
|
+
for (const [literal, normalized] of literalsWithExpandedYear) {
|
|
200
|
+
strictEqual(normalizeDateTimeLiteral(literal), normalized);
|
|
201
|
+
strictEqual(typeof Temporal.Instant.from(normalized), "object");
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
test("normalizeDateTimeLiteral() is idempotent", () => {
|
|
205
|
+
const literals = [
|
|
206
|
+
...literalsWithOffset,
|
|
207
|
+
...literalsWithoutOffset,
|
|
208
|
+
...literalsWithoutSeconds.map(([literal]) => literal),
|
|
209
|
+
...literalsWithExpandedYear.map(([literal]) => literal),
|
|
210
|
+
"2024-01-01"
|
|
211
|
+
];
|
|
212
|
+
for (const literal of literals) {
|
|
213
|
+
const normalized = normalizeDateTimeLiteral(literal);
|
|
214
|
+
strictEqual(normalizeDateTimeLiteral(normalized), normalized);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
133
217
|
//#endregion
|
|
134
218
|
export {};
|
package/package.json
CHANGED
package/src/temporal.test.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { strictEqual } from "node:assert";
|
|
3
3
|
import { test } from "node:test";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
isTemporalDuration,
|
|
6
|
+
isTemporalInstant,
|
|
7
|
+
normalizeDateTimeLiteral,
|
|
8
|
+
} from "./temporal.ts";
|
|
5
9
|
|
|
6
10
|
test("isTemporalInstant() accepts polyfill instances", () => {
|
|
7
11
|
strictEqual(
|
|
@@ -119,3 +123,89 @@ test("isTemporalDuration() rejects default Object.prototype.toString", () => {
|
|
|
119
123
|
};
|
|
120
124
|
strictEqual(isTemporalDuration(decoy), false);
|
|
121
125
|
});
|
|
126
|
+
|
|
127
|
+
const literalsWithOffset = [
|
|
128
|
+
"2024-01-01T10:00Z",
|
|
129
|
+
"2024-01-01T10:00+09:00",
|
|
130
|
+
"2024-01-01T10:00-05:00",
|
|
131
|
+
"2024-01-01T10:00:00Z",
|
|
132
|
+
"2024-01-01T10:00:00+09:00",
|
|
133
|
+
"2024-01-01T10:00:00-05:00",
|
|
134
|
+
"2024-01-01T10:00:00+0900",
|
|
135
|
+
"2024-01-01T10:00:00.123456789Z",
|
|
136
|
+
"2024-01-01t10:00z",
|
|
137
|
+
"2024-01-01 10:00:00Z",
|
|
138
|
+
] as const;
|
|
139
|
+
|
|
140
|
+
const literalsWithoutOffset = [
|
|
141
|
+
"2024-01-01T10:00",
|
|
142
|
+
"2024-01-01T10:00:00",
|
|
143
|
+
"2024-01-01T10:00:00.123",
|
|
144
|
+
"2025-01-01 12:34:56",
|
|
145
|
+
] as const;
|
|
146
|
+
|
|
147
|
+
const literalsWithoutSeconds = [
|
|
148
|
+
["2024-01-01T10:00.5Z", "2024-01-01T10:00:00.5Z"],
|
|
149
|
+
["2024-01-01T10:00.5+09:00", "2024-01-01T10:00:00.5+09:00"],
|
|
150
|
+
["2024-01-01T10:00.5-05:00", "2024-01-01T10:00:00.5-05:00"],
|
|
151
|
+
["2024-01-01T10:00.5", "2024-01-01T10:00:00.5Z"],
|
|
152
|
+
["2024-01-01T10:00.123456789Z", "2024-01-01T10:00:00.123456789Z"],
|
|
153
|
+
] as const;
|
|
154
|
+
|
|
155
|
+
const literalsWithExpandedYear = [
|
|
156
|
+
["+002024-01-01T10:00", "+002024-01-01T10:00Z"],
|
|
157
|
+
["-000001-01-01T10:00.5Z", "-000001-01-01T10:00:00.5Z"],
|
|
158
|
+
] as const;
|
|
159
|
+
|
|
160
|
+
test("normalizeDateTimeLiteral() keeps literals with a UTC offset", () => {
|
|
161
|
+
for (const literal of literalsWithOffset) {
|
|
162
|
+
strictEqual(normalizeDateTimeLiteral(literal), literal);
|
|
163
|
+
strictEqual(typeof Temporal.Instant.from(literal), "object");
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("normalizeDateTimeLiteral() treats literals without an offset as UTC", () => {
|
|
168
|
+
for (const literal of literalsWithoutOffset) {
|
|
169
|
+
strictEqual(normalizeDateTimeLiteral(literal), `${literal}Z`);
|
|
170
|
+
strictEqual(
|
|
171
|
+
typeof Temporal.Instant.from(normalizeDateTimeLiteral(literal)),
|
|
172
|
+
"object",
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test("normalizeDateTimeLiteral() keeps literals without a time part", () => {
|
|
178
|
+
strictEqual(normalizeDateTimeLiteral("2024-01-01"), "2024-01-01");
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test("normalizeDateTimeLiteral() inserts omitted seconds before a fraction", () => {
|
|
182
|
+
for (const [literal, normalized] of literalsWithoutSeconds) {
|
|
183
|
+
strictEqual(normalizeDateTimeLiteral(literal), normalized);
|
|
184
|
+
strictEqual(typeof Temporal.Instant.from(normalized), "object");
|
|
185
|
+
}
|
|
186
|
+
strictEqual(
|
|
187
|
+
normalizeDateTimeLiteral("2024-01-01T10:00:00.5Z"),
|
|
188
|
+
"2024-01-01T10:00:00.5Z",
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test("normalizeDateTimeLiteral() handles expanded years", () => {
|
|
193
|
+
for (const [literal, normalized] of literalsWithExpandedYear) {
|
|
194
|
+
strictEqual(normalizeDateTimeLiteral(literal), normalized);
|
|
195
|
+
strictEqual(typeof Temporal.Instant.from(normalized), "object");
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("normalizeDateTimeLiteral() is idempotent", () => {
|
|
200
|
+
const literals = [
|
|
201
|
+
...literalsWithOffset,
|
|
202
|
+
...literalsWithoutOffset,
|
|
203
|
+
...literalsWithoutSeconds.map(([literal]) => literal),
|
|
204
|
+
...literalsWithExpandedYear.map(([literal]) => literal),
|
|
205
|
+
"2024-01-01",
|
|
206
|
+
];
|
|
207
|
+
for (const literal of literals) {
|
|
208
|
+
const normalized = normalizeDateTimeLiteral(literal);
|
|
209
|
+
strictEqual(normalizeDateTimeLiteral(normalized), normalized);
|
|
210
|
+
}
|
|
211
|
+
});
|
package/src/temporal.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Type guards for `Temporal` namespace objects
|
|
2
|
+
* Type guards for `Temporal` namespace objects and normalization of
|
|
3
|
+
* `xsd:dateTime` literals.
|
|
3
4
|
*
|
|
4
5
|
* Fedify accepts both runtime polyfills (e.g. `@js-temporal/polyfill`,
|
|
5
6
|
* `temporal-polyfill`) and the host's native `Temporal` implementation
|
|
@@ -72,3 +73,21 @@ export function isTemporalDuration(value: unknown): value is Temporal.Duration {
|
|
|
72
73
|
value.toString !== Object.prototype.toString
|
|
73
74
|
);
|
|
74
75
|
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Normalizes an `xsd:dateTime` literal into a form that
|
|
79
|
+
* `Temporal.Instant.from()` accepts. A literal without a UTC offset is
|
|
80
|
+
* treated as UTC, and seconds omitted before a fraction, which Activity Streams
|
|
81
|
+
* 2.0 allows, are filled in.
|
|
82
|
+
*
|
|
83
|
+
* @param value The date-time literal to normalize.
|
|
84
|
+
* @returns The normalized literal.
|
|
85
|
+
*/
|
|
86
|
+
export function normalizeDateTimeLiteral(value: string): string {
|
|
87
|
+
const timeStart = value.search(/[Tt ]/) + 1;
|
|
88
|
+
if (timeStart < 1) return value;
|
|
89
|
+
const date = value.substring(0, timeStart);
|
|
90
|
+
const time = value.substring(timeStart)
|
|
91
|
+
.replace(/^(\d{2}:\d{2})(?=\.)/, "$1:00");
|
|
92
|
+
return date + (/[Zz+-]/.test(time) ? time : time + "Z");
|
|
93
|
+
}
|