@fedify/fedify 1.6.0-dev.812 → 1.6.0-dev.814

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 (120) hide show
  1. package/esm/deno.js +1 -2
  2. package/esm/federation/handler.js +3 -2
  3. package/esm/{deps/jsr.io/@std/http/1.0.16/_negotiation/media_type.js → federation/negotiation.js} +14 -62
  4. package/esm/nodeinfo/client.js +2 -2
  5. package/esm/nodeinfo/mod.js +1 -1
  6. package/esm/nodeinfo/semver.js +150 -0
  7. package/esm/nodeinfo/types.js +2 -2
  8. package/esm/vocab/vocab.js +176 -176
  9. package/package.json +1 -1
  10. package/types/deno.d.ts +0 -1
  11. package/types/federation/handler.d.ts.map +1 -1
  12. package/types/{deps/jsr.io/@std/http/1.0.16/_negotiation/common.d.ts → federation/negotiation.d.ts} +2 -3
  13. package/types/federation/negotiation.d.ts.map +1 -0
  14. package/types/nodeinfo/client.d.ts.map +1 -1
  15. package/types/nodeinfo/mod.d.ts +1 -1
  16. package/types/nodeinfo/mod.d.ts.map +1 -1
  17. package/types/nodeinfo/semver.d.ts +71 -0
  18. package/types/nodeinfo/semver.d.ts.map +1 -0
  19. package/types/nodeinfo/types.d.ts +1 -1
  20. package/types/nodeinfo/types.d.ts.map +1 -1
  21. package/esm/deps/jsr.io/@std/http/1.0.16/_negotiation/common.js +0 -40
  22. package/esm/deps/jsr.io/@std/http/1.0.16/_negotiation/encoding.js +0 -123
  23. package/esm/deps/jsr.io/@std/http/1.0.16/_negotiation/language.js +0 -113
  24. package/esm/deps/jsr.io/@std/http/1.0.16/negotiation.js +0 -37
  25. package/esm/deps/jsr.io/@std/semver/1.0.5/_constants.js +0 -28
  26. package/esm/deps/jsr.io/@std/semver/1.0.5/_shared.js +0 -162
  27. package/esm/deps/jsr.io/@std/semver/1.0.5/_test_comparator_set.js +0 -58
  28. package/esm/deps/jsr.io/@std/semver/1.0.5/can_parse.js +0 -27
  29. package/esm/deps/jsr.io/@std/semver/1.0.5/compare.js +0 -35
  30. package/esm/deps/jsr.io/@std/semver/1.0.5/difference.js +0 -41
  31. package/esm/deps/jsr.io/@std/semver/1.0.5/equals.js +0 -27
  32. package/esm/deps/jsr.io/@std/semver/1.0.5/format.js +0 -32
  33. package/esm/deps/jsr.io/@std/semver/1.0.5/format_range.js +0 -27
  34. package/esm/deps/jsr.io/@std/semver/1.0.5/greater_or_equal.js +0 -26
  35. package/esm/deps/jsr.io/@std/semver/1.0.5/greater_than.js +0 -28
  36. package/esm/deps/jsr.io/@std/semver/1.0.5/greater_than_range.js +0 -58
  37. package/esm/deps/jsr.io/@std/semver/1.0.5/increment.js +0 -176
  38. package/esm/deps/jsr.io/@std/semver/1.0.5/is_range.js +0 -38
  39. package/esm/deps/jsr.io/@std/semver/1.0.5/is_semver.js +0 -53
  40. package/esm/deps/jsr.io/@std/semver/1.0.5/less_or_equal.js +0 -26
  41. package/esm/deps/jsr.io/@std/semver/1.0.5/less_than.js +0 -26
  42. package/esm/deps/jsr.io/@std/semver/1.0.5/less_than_range.js +0 -58
  43. package/esm/deps/jsr.io/@std/semver/1.0.5/max_satisfying.js +0 -30
  44. package/esm/deps/jsr.io/@std/semver/1.0.5/min_satisfying.js +0 -30
  45. package/esm/deps/jsr.io/@std/semver/1.0.5/mod.js +0 -300
  46. package/esm/deps/jsr.io/@std/semver/1.0.5/not_equals.js +0 -25
  47. package/esm/deps/jsr.io/@std/semver/1.0.5/parse.js +0 -44
  48. package/esm/deps/jsr.io/@std/semver/1.0.5/parse_range.js +0 -358
  49. package/esm/deps/jsr.io/@std/semver/1.0.5/range_intersects.js +0 -89
  50. package/esm/deps/jsr.io/@std/semver/1.0.5/satisfies.js +0 -27
  51. package/esm/deps/jsr.io/@std/semver/1.0.5/try_parse.js +0 -27
  52. package/esm/deps/jsr.io/@std/semver/1.0.5/try_parse_range.js +0 -33
  53. package/esm/deps/jsr.io/@std/semver/1.0.5/types.js +0 -3
  54. package/types/deps/jsr.io/@std/http/1.0.16/_negotiation/common.d.ts.map +0 -1
  55. package/types/deps/jsr.io/@std/http/1.0.16/_negotiation/encoding.d.ts +0 -34
  56. package/types/deps/jsr.io/@std/http/1.0.16/_negotiation/encoding.d.ts.map +0 -1
  57. package/types/deps/jsr.io/@std/http/1.0.16/_negotiation/language.d.ts +0 -31
  58. package/types/deps/jsr.io/@std/http/1.0.16/_negotiation/language.d.ts.map +0 -1
  59. package/types/deps/jsr.io/@std/http/1.0.16/_negotiation/media_type.d.ts +0 -31
  60. package/types/deps/jsr.io/@std/http/1.0.16/_negotiation/media_type.d.ts.map +0 -1
  61. package/types/deps/jsr.io/@std/http/1.0.16/negotiation.d.ts +0 -148
  62. package/types/deps/jsr.io/@std/http/1.0.16/negotiation.d.ts.map +0 -1
  63. package/types/deps/jsr.io/@std/semver/1.0.5/_constants.d.ts +0 -12
  64. package/types/deps/jsr.io/@std/semver/1.0.5/_constants.d.ts.map +0 -1
  65. package/types/deps/jsr.io/@std/semver/1.0.5/_shared.d.ts +0 -44
  66. package/types/deps/jsr.io/@std/semver/1.0.5/_shared.d.ts.map +0 -1
  67. package/types/deps/jsr.io/@std/semver/1.0.5/_test_comparator_set.d.ts +0 -3
  68. package/types/deps/jsr.io/@std/semver/1.0.5/_test_comparator_set.d.ts.map +0 -1
  69. package/types/deps/jsr.io/@std/semver/1.0.5/can_parse.d.ts +0 -17
  70. package/types/deps/jsr.io/@std/semver/1.0.5/can_parse.d.ts.map +0 -1
  71. package/types/deps/jsr.io/@std/semver/1.0.5/compare.d.ts +0 -28
  72. package/types/deps/jsr.io/@std/semver/1.0.5/compare.d.ts.map +0 -1
  73. package/types/deps/jsr.io/@std/semver/1.0.5/difference.d.ts +0 -27
  74. package/types/deps/jsr.io/@std/semver/1.0.5/difference.d.ts.map +0 -1
  75. package/types/deps/jsr.io/@std/semver/1.0.5/equals.d.ts +0 -24
  76. package/types/deps/jsr.io/@std/semver/1.0.5/equals.d.ts.map +0 -1
  77. package/types/deps/jsr.io/@std/semver/1.0.5/format.d.ts +0 -22
  78. package/types/deps/jsr.io/@std/semver/1.0.5/format.d.ts.map +0 -1
  79. package/types/deps/jsr.io/@std/semver/1.0.5/format_range.d.ts +0 -18
  80. package/types/deps/jsr.io/@std/semver/1.0.5/format_range.d.ts.map +0 -1
  81. package/types/deps/jsr.io/@std/semver/1.0.5/greater_or_equal.d.ts +0 -25
  82. package/types/deps/jsr.io/@std/semver/1.0.5/greater_or_equal.d.ts.map +0 -1
  83. package/types/deps/jsr.io/@std/semver/1.0.5/greater_than.d.ts +0 -25
  84. package/types/deps/jsr.io/@std/semver/1.0.5/greater_than.d.ts.map +0 -1
  85. package/types/deps/jsr.io/@std/semver/1.0.5/greater_than_range.d.ts +0 -23
  86. package/types/deps/jsr.io/@std/semver/1.0.5/greater_than_range.d.ts.map +0 -1
  87. package/types/deps/jsr.io/@std/semver/1.0.5/increment.d.ts +0 -51
  88. package/types/deps/jsr.io/@std/semver/1.0.5/increment.d.ts.map +0 -1
  89. package/types/deps/jsr.io/@std/semver/1.0.5/is_range.d.ts +0 -23
  90. package/types/deps/jsr.io/@std/semver/1.0.5/is_range.d.ts.map +0 -1
  91. package/types/deps/jsr.io/@std/semver/1.0.5/is_semver.d.ts +0 -34
  92. package/types/deps/jsr.io/@std/semver/1.0.5/is_semver.d.ts.map +0 -1
  93. package/types/deps/jsr.io/@std/semver/1.0.5/less_or_equal.d.ts +0 -25
  94. package/types/deps/jsr.io/@std/semver/1.0.5/less_or_equal.d.ts.map +0 -1
  95. package/types/deps/jsr.io/@std/semver/1.0.5/less_than.d.ts +0 -25
  96. package/types/deps/jsr.io/@std/semver/1.0.5/less_than.d.ts.map +0 -1
  97. package/types/deps/jsr.io/@std/semver/1.0.5/less_than_range.d.ts +0 -23
  98. package/types/deps/jsr.io/@std/semver/1.0.5/less_than_range.d.ts.map +0 -1
  99. package/types/deps/jsr.io/@std/semver/1.0.5/max_satisfying.d.ts +0 -22
  100. package/types/deps/jsr.io/@std/semver/1.0.5/max_satisfying.d.ts.map +0 -1
  101. package/types/deps/jsr.io/@std/semver/1.0.5/min_satisfying.d.ts +0 -22
  102. package/types/deps/jsr.io/@std/semver/1.0.5/min_satisfying.d.ts.map +0 -1
  103. package/types/deps/jsr.io/@std/semver/1.0.5/mod.d.ts +0 -298
  104. package/types/deps/jsr.io/@std/semver/1.0.5/mod.d.ts.map +0 -1
  105. package/types/deps/jsr.io/@std/semver/1.0.5/not_equals.d.ts +0 -24
  106. package/types/deps/jsr.io/@std/semver/1.0.5/not_equals.d.ts.map +0 -1
  107. package/types/deps/jsr.io/@std/semver/1.0.5/parse.d.ts +0 -25
  108. package/types/deps/jsr.io/@std/semver/1.0.5/parse.d.ts.map +0 -1
  109. package/types/deps/jsr.io/@std/semver/1.0.5/parse_range.d.ts +0 -27
  110. package/types/deps/jsr.io/@std/semver/1.0.5/parse_range.d.ts.map +0 -1
  111. package/types/deps/jsr.io/@std/semver/1.0.5/range_intersects.d.ts +0 -25
  112. package/types/deps/jsr.io/@std/semver/1.0.5/range_intersects.d.ts.map +0 -1
  113. package/types/deps/jsr.io/@std/semver/1.0.5/satisfies.d.ts +0 -24
  114. package/types/deps/jsr.io/@std/semver/1.0.5/satisfies.d.ts.map +0 -1
  115. package/types/deps/jsr.io/@std/semver/1.0.5/try_parse.d.ts +0 -21
  116. package/types/deps/jsr.io/@std/semver/1.0.5/try_parse.d.ts.map +0 -1
  117. package/types/deps/jsr.io/@std/semver/1.0.5/try_parse_range.d.ts +0 -23
  118. package/types/deps/jsr.io/@std/semver/1.0.5/try_parse_range.d.ts.map +0 -1
  119. package/types/deps/jsr.io/@std/semver/1.0.5/types.d.ts +0 -58
  120. package/types/deps/jsr.io/@std/semver/1.0.5/types.d.ts.map +0 -1
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "@fedify/fedify",
3
- "version": "1.6.0-dev.812+f522d042",
3
+ "version": "1.6.0-dev.814+26348fc2",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./mod.ts",
@@ -25,7 +25,6 @@ export default {
25
25
  "@opentelemetry/semantic-conventions": "npm:@opentelemetry/semantic-conventions@^1.27.0",
26
26
  "@phensley/language-tag": "npm:@phensley/language-tag@^1.9.0",
27
27
  "@std/assert": "jsr:@std/assert@^0.226.0",
28
- "@std/http": "jsr:@std/http@^1.0.6",
29
28
  "@std/testing": "jsr:@std/testing@^0.224.0",
30
29
  "@std/url": "jsr:@std/url@^0.225.1",
31
30
  "@std/yaml": "jsr:@std/yaml@^0.224.3",
@@ -1,6 +1,5 @@
1
1
  import { getLogger } from "@logtape/logtape";
2
2
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
3
- import { accepts } from "../deps/jsr.io/@std/http/1.0.16/negotiation.js";
4
3
  import metadata from "../deno.js";
5
4
  import { verifyRequest } from "../sig/http.js";
6
5
  import { detachSignature, verifyJsonLd } from "../sig/ld.js";
@@ -10,8 +9,10 @@ import { getTypeId } from "../vocab/type.js";
10
9
  import { Activity, Link, Object, OrderedCollection, OrderedCollectionPage, } from "../vocab/vocab.js";
11
10
  import { routeActivity } from "./inbox.js";
12
11
  import { KvKeyCache } from "./keycache.js";
12
+ import { preferredMediaTypes } from "./negotiation.js";
13
13
  export function acceptsJsonLd(request) {
14
- const types = accepts(request);
14
+ const accept = request.headers.get("Accept");
15
+ const types = accept ? preferredMediaTypes(accept) : ["*/*"];
15
16
  if (types == null)
16
17
  return true;
17
18
  if (types[0] === "text/html" || types[0] === "application/xhtml+xml") {
@@ -1,4 +1,3 @@
1
- // Copyright 2018-2025 the Deno authors. MIT license.
2
1
  /*!
3
2
  * Adapted directly from negotiator at https://github.com/jshttp/negotiator/
4
3
  * which is licensed as follows:
@@ -28,7 +27,16 @@
28
27
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29
28
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
29
  */
31
- import { compareSpecs, isQuality } from "./common.js";
30
+ function compareSpecs(a, b) {
31
+ return (b.q - a.q ||
32
+ (b.s ?? 0) - (a.s ?? 0) ||
33
+ (a.o ?? 0) - (b.o ?? 0) ||
34
+ a.i - b.i ||
35
+ 0);
36
+ }
37
+ function isQuality(spec) {
38
+ return spec.q > 0;
39
+ }
32
40
  const simpleMediaTypeRegExp = /^\s*([^\s\/;]+)\/([^;\s]+)\s*(?:;(.*))?$/;
33
41
  function splitKeyValuePair(str) {
34
42
  const [key, value] = str.split("=");
@@ -74,67 +82,11 @@ function parseAccept(accept) {
74
82
  function getFullType(spec) {
75
83
  return `${spec.type}/${spec.subtype}`;
76
84
  }
77
- function specify(type, spec, index) {
78
- const p = parseMediaType(type, index);
79
- if (!p) {
80
- return;
81
- }
82
- let s = 0;
83
- if (spec.type.toLowerCase() === p.type.toLowerCase()) {
84
- s |= 4;
85
- }
86
- else if (spec.type !== "*") {
87
- return;
88
- }
89
- if (spec.subtype.toLowerCase() === p.subtype.toLowerCase()) {
90
- s |= 2;
91
- }
92
- else if (spec.subtype !== "*") {
93
- return;
94
- }
95
- const keys = Object.keys(spec.params);
96
- if (keys.length) {
97
- if (keys.every((key) => (spec.params[key] ?? "").toLowerCase() ===
98
- (p.params[key] ?? "").toLowerCase())) {
99
- s |= 1;
100
- }
101
- else {
102
- return;
103
- }
104
- }
105
- return {
106
- i: index,
107
- o: spec.o,
108
- q: spec.q,
109
- s,
110
- };
111
- }
112
- function getMediaTypePriority(type, accepted, index) {
113
- let priority = { o: -1, q: 0, s: 0, i: index };
114
- for (const accepts of accepted) {
115
- const spec = specify(type, accepts, index);
116
- if (spec &&
117
- ((priority.s ?? 0) - (spec.s ?? 0) ||
118
- (priority.q ?? 0) - (spec.q ?? 0) ||
119
- (priority.o ?? 0) - (spec.o ?? 0)) < 0) {
120
- priority = spec;
121
- }
122
- }
123
- return priority;
124
- }
125
- export function preferredMediaTypes(accept, provided) {
85
+ export function preferredMediaTypes(accept) {
126
86
  const accepts = parseAccept(accept === undefined ? "*/*" : accept ?? "");
127
- if (!provided) {
128
- return accepts
129
- .filter(isQuality)
130
- .sort(compareSpecs)
131
- .map(getFullType);
132
- }
133
- const priorities = provided.map((type, index) => {
134
- return getMediaTypePriority(type, accepts, index);
135
- });
136
- return priorities
87
+ return accepts
137
88
  .filter(isQuality)
138
89
  .sort(compareSpecs)
139
- .map((priority) => provided[priorities.indexOf(priority)]);
90
+ .map(getFullType);
140
91
  }
92
+ // cSpell: ignore Schlueter kvps
@@ -1,6 +1,6 @@
1
1
  import { getLogger } from "@logtape/logtape";
2
- import { parse } from "../deps/jsr.io/@std/semver/1.0.5/mod.js";
3
2
  import { getUserAgent, } from "../runtime/docloader.js";
3
+ import { parseSemVer } from "./semver.js";
4
4
  const logger = getLogger(["fedify", "nodeinfo", "client"]);
5
5
  export async function getNodeInfo(url, options = {}) {
6
6
  try {
@@ -169,7 +169,7 @@ export function parseSoftware(data, options = {}) {
169
169
  let version;
170
170
  if ("version" in data && typeof data.version === "string") {
171
171
  try {
172
- version = parse(data.version);
172
+ version = parseSemVer(data.version);
173
173
  }
174
174
  catch {
175
175
  if (!options.tryBestEffort)
@@ -6,6 +6,6 @@
6
6
  * @since 0.2.0
7
7
  */
8
8
  import "../_dnt.polyfills.js";
9
- export { format as formatSemVer, parse as parseSemVer, } from "../deps/jsr.io/@std/semver/1.0.5/mod.js";
9
+ export { formatSemVer, parseSemVer } from "./semver.js";
10
10
  export { getNodeInfo, parseNodeInfo, } from "./client.js";
11
11
  export * from "./types.js";
@@ -0,0 +1,150 @@
1
+ // Adopted from Deno's @std/semver
2
+ const MAX_LENGTH = 256;
3
+ /**
4
+ * A single `0`, or a non-zero digit followed by zero or more digits.
5
+ */
6
+ const NUMERIC_IDENTIFIER = "0|[1-9]\\d*";
7
+ /**
8
+ * Zero or more digits, followed by a letter or hyphen, and then zero or more letters, digits, or hyphens.
9
+ */
10
+ const NON_NUMERIC_IDENTIFIER = "\\d*[a-zA-Z-][a-zA-Z0-9-]*";
11
+ /**
12
+ * Three dot-separated numeric identifiers.
13
+ */
14
+ const VERSION_CORE = `(?<major>${NUMERIC_IDENTIFIER})\\.(?<minor>${NUMERIC_IDENTIFIER})\\.(?<patch>${NUMERIC_IDENTIFIER})`;
15
+ /**
16
+ * A numeric identifier, or a non-numeric identifier.
17
+ */
18
+ const PRERELEASE_IDENTIFIER = `(?:${NUMERIC_IDENTIFIER}|${NON_NUMERIC_IDENTIFIER})`;
19
+ /**
20
+ * A hyphen, followed by one or more dot-separated pre-release version identifiers.
21
+ * @example "-pre.release"
22
+ */
23
+ const PRERELEASE = `(?:-(?<prerelease>${PRERELEASE_IDENTIFIER}(?:\\.${PRERELEASE_IDENTIFIER})*))`;
24
+ /**
25
+ * Any combination of digits, letters, or hyphens.
26
+ */
27
+ const BUILD_IDENTIFIER = "[0-9A-Za-z-]+";
28
+ /**
29
+ * A plus sign, followed by one or more period-separated build metadata identifiers.
30
+ * @example "+build.meta"
31
+ */
32
+ const BUILD = `(?:\\+(?<buildmetadata>${BUILD_IDENTIFIER}(?:\\.${BUILD_IDENTIFIER})*))`;
33
+ /**
34
+ * A version, followed optionally by a pre-release version and build metadata.
35
+ */
36
+ const FULL_VERSION = `v?${VERSION_CORE}${PRERELEASE}?${BUILD}?`;
37
+ export const FULL_REGEXP = new RegExp(`^${FULL_VERSION}$`);
38
+ /**
39
+ * Attempt to parse a string as a semantic version, returning a SemVer object.
40
+ *
41
+ * @example Usage
42
+ * ```ts
43
+ * import { parseSemVer } from "@fedify/fedify/nodeinfo";
44
+ * import { assertEquals } from "@std/assert";
45
+ *
46
+ * const version = parseSemVer("1.2.3");
47
+ * assertEquals(version, {
48
+ * major: 1,
49
+ * minor: 2,
50
+ * patch: 3,
51
+ * prerelease: [],
52
+ * build: [],
53
+ * });
54
+ * ```
55
+ *
56
+ * @throws {TypeError} If the input string is invalid.
57
+ * @param value The version string to parse
58
+ * @returns A valid SemVer
59
+ * @since 1.2.0
60
+ */
61
+ export function parseSemVer(value) {
62
+ if (typeof value !== "string") {
63
+ throw new TypeError(`Cannot parse version as version must be a string: received ${typeof value}`);
64
+ }
65
+ if (value.length > MAX_LENGTH) {
66
+ throw new TypeError(`Cannot parse version as version length is too long: length is ${value.length}, max length is ${MAX_LENGTH}`);
67
+ }
68
+ value = value.trim();
69
+ const groups = value.match(FULL_REGEXP)?.groups;
70
+ if (!groups)
71
+ throw new TypeError(`Cannot parse version: ${value}`);
72
+ const major = parseNumber(groups.major, `Cannot parse version ${value}: invalid major version`);
73
+ const minor = parseNumber(groups.minor, `Cannot parse version ${value}: invalid minor version`);
74
+ const patch = parseNumber(groups.patch, `Cannot parse version ${value}: invalid patch version`);
75
+ const prerelease = groups.prerelease
76
+ ? parsePrerelease(groups.prerelease)
77
+ : [];
78
+ const build = groups.buildmetadata ? parseBuild(groups.buildmetadata) : [];
79
+ return { major, minor, patch, prerelease, build };
80
+ }
81
+ /**
82
+ * Returns true if the value is a valid SemVer number.
83
+ *
84
+ * Must be a number. Must not be NaN. Can be positive or negative infinity.
85
+ * Can be between 0 and MAX_SAFE_INTEGER.
86
+ * @param value The value to check
87
+ * @returns True if its a valid semver number
88
+ */
89
+ function isValidNumber(value) {
90
+ return (typeof value === "number" &&
91
+ !Number.isNaN(value) &&
92
+ (!Number.isFinite(value) ||
93
+ (0 <= value && value <= Number.MAX_SAFE_INTEGER)));
94
+ }
95
+ const NUMERIC_IDENTIFIER_REGEXP = new RegExp(`^${NUMERIC_IDENTIFIER}$`);
96
+ function parsePrerelease(prerelease) {
97
+ return prerelease
98
+ .split(".")
99
+ .filter(Boolean)
100
+ .map((id) => {
101
+ if (NUMERIC_IDENTIFIER_REGEXP.test(id)) {
102
+ const number = Number(id);
103
+ if (isValidNumber(number))
104
+ return number;
105
+ }
106
+ return id;
107
+ });
108
+ }
109
+ function parseBuild(buildmetadata) {
110
+ return buildmetadata.split(".").filter(Boolean);
111
+ }
112
+ function parseNumber(input, errorMessage) {
113
+ const number = Number(input);
114
+ if (!isValidNumber(number))
115
+ throw new TypeError(errorMessage);
116
+ return number;
117
+ }
118
+ function formatNumber(value) {
119
+ return value.toFixed(0);
120
+ }
121
+ /**
122
+ * Format a SemVer object into a string.
123
+ *
124
+ * @example Usage
125
+ * ```ts
126
+ * import { formatSemVer } from "@fedify/fedify/nodeinfo";
127
+ * import { assertEquals } from "@std/assert";
128
+ *
129
+ * const semver = {
130
+ * major: 1,
131
+ * minor: 2,
132
+ * patch: 3,
133
+ * };
134
+ * assertEquals(formatSemVer(semver), "1.2.3");
135
+ * ```
136
+ *
137
+ * @param version The SemVer to format
138
+ * @returns The string representation of a semantic version.
139
+ * @since 1.2.0
140
+ */
141
+ export function formatSemVer(version) {
142
+ const major = formatNumber(version.major);
143
+ const minor = formatNumber(version.minor);
144
+ const patch = formatNumber(version.patch);
145
+ const pre = version.prerelease?.join(".") ?? "";
146
+ const build = version.build?.join(".") ?? "";
147
+ const primary = `${major}.${minor}.${patch}`;
148
+ const release = [primary, pre].filter((v) => v).join("-");
149
+ return [release, build].filter((v) => v).join("+");
150
+ }
@@ -1,4 +1,4 @@
1
- import { format } from "../deps/jsr.io/@std/semver/1.0.5/mod.js";
1
+ import { formatSemVer } from "./semver.js";
2
2
  /**
3
3
  * Converts a {@link NodeInfo} object to a JSON value.
4
4
  * @param nodeInfo The {@link NodeInfo} object to convert.
@@ -40,7 +40,7 @@ export function nodeInfoToJson(nodeInfo) {
40
40
  version: "2.1",
41
41
  software: {
42
42
  name: nodeInfo.software.name,
43
- version: format(nodeInfo.software.version),
43
+ version: formatSemVer(nodeInfo.software.version),
44
44
  repository: nodeInfo.software.repository?.href,
45
45
  homepage: nodeInfo.software.homepage?.href,
46
46
  },