@uncefact/untp-utils 0.0.1 → 0.2.0

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 (221) hide show
  1. package/LICENSE +202 -674
  2. package/README.md +23 -1
  3. package/build/artefacts/detect-version-from-context.d.ts +46 -0
  4. package/build/artefacts/detect-version-from-context.js +77 -0
  5. package/build/artefacts/detect-version-from-context.js.map +1 -0
  6. package/build/artefacts/detect-version-from-context.test.d.ts +1 -0
  7. package/build/artefacts/detect-version-from-context.test.js +69 -0
  8. package/build/artefacts/detect-version-from-context.test.js.map +1 -0
  9. package/build/artefacts/index.d.ts +3 -0
  10. package/build/artefacts/index.js +4 -0
  11. package/build/artefacts/index.js.map +1 -0
  12. package/build/artefacts/urls.d.ts +79 -0
  13. package/build/artefacts/urls.js +133 -0
  14. package/build/artefacts/urls.js.map +1 -0
  15. package/build/artefacts/urls.test.d.ts +1 -0
  16. package/build/artefacts/urls.test.js +91 -0
  17. package/build/artefacts/urls.test.js.map +1 -0
  18. package/build/artefacts/version.d.ts +9 -0
  19. package/build/artefacts/version.js +17 -0
  20. package/build/artefacts/version.js.map +1 -0
  21. package/build/artefacts/version.test.d.ts +1 -0
  22. package/build/artefacts/version.test.js +16 -0
  23. package/build/artefacts/version.test.js.map +1 -0
  24. package/build/cache/in-memory-ttl-cache.d.ts +2 -0
  25. package/build/cache/in-memory-ttl-cache.js +76 -0
  26. package/build/cache/in-memory-ttl-cache.js.map +1 -0
  27. package/build/cache/in-memory-ttl-cache.test.d.ts +1 -0
  28. package/build/cache/in-memory-ttl-cache.test.js +236 -0
  29. package/build/cache/in-memory-ttl-cache.test.js.map +1 -0
  30. package/build/cache/index.d.ts +2 -0
  31. package/build/cache/index.js +2 -0
  32. package/build/cache/index.js.map +1 -0
  33. package/build/cache/ttl-cache.d.ts +22 -0
  34. package/build/cache/ttl-cache.js +2 -0
  35. package/build/cache/ttl-cache.js.map +1 -0
  36. package/build/common/as-non-empty-string.d.ts +7 -0
  37. package/build/common/as-non-empty-string.js +10 -0
  38. package/build/common/as-non-empty-string.js.map +1 -0
  39. package/build/common/as-non-empty-string.test.d.ts +1 -0
  40. package/build/common/as-non-empty-string.test.js +25 -0
  41. package/build/common/as-non-empty-string.test.js.map +1 -0
  42. package/build/common/require-string.d.ts +12 -0
  43. package/build/common/require-string.js +27 -0
  44. package/build/common/require-string.js.map +1 -0
  45. package/build/common/require-string.test.d.ts +1 -0
  46. package/build/common/require-string.test.js +53 -0
  47. package/build/common/require-string.test.js.map +1 -0
  48. package/build/conformity-vocabulary/codes.d.ts +10 -0
  49. package/build/conformity-vocabulary/codes.js +10 -0
  50. package/build/conformity-vocabulary/codes.js.map +1 -0
  51. package/build/conformity-vocabulary/errors.d.ts +44 -0
  52. package/build/conformity-vocabulary/errors.js +68 -0
  53. package/build/conformity-vocabulary/errors.js.map +1 -0
  54. package/build/conformity-vocabulary/index.d.ts +6 -0
  55. package/build/conformity-vocabulary/index.js +7 -0
  56. package/build/conformity-vocabulary/index.js.map +1 -0
  57. package/build/conformity-vocabulary/parse-conformity-catalogue.d.ts +26 -0
  58. package/build/conformity-vocabulary/parse-conformity-catalogue.js +106 -0
  59. package/build/conformity-vocabulary/parse-conformity-catalogue.js.map +1 -0
  60. package/build/conformity-vocabulary/parse-conformity-catalogue.test.d.ts +1 -0
  61. package/build/conformity-vocabulary/parse-conformity-catalogue.test.js +327 -0
  62. package/build/conformity-vocabulary/parse-conformity-catalogue.test.js.map +1 -0
  63. package/build/conformity-vocabulary/parse-conformity-scheme.d.ts +28 -0
  64. package/build/conformity-vocabulary/parse-conformity-scheme.js +47 -0
  65. package/build/conformity-vocabulary/parse-conformity-scheme.js.map +1 -0
  66. package/build/conformity-vocabulary/parse-conformity-scheme.test.d.ts +1 -0
  67. package/build/conformity-vocabulary/parse-conformity-scheme.test.js +284 -0
  68. package/build/conformity-vocabulary/parse-conformity-scheme.test.js.map +1 -0
  69. package/build/conformity-vocabulary/parsers/v0-7-0.parser.d.ts +19 -0
  70. package/build/conformity-vocabulary/parsers/v0-7-0.parser.js +219 -0
  71. package/build/conformity-vocabulary/parsers/v0-7-0.parser.js.map +1 -0
  72. package/build/conformity-vocabulary/types.d.ts +180 -0
  73. package/build/conformity-vocabulary/types.js +2 -0
  74. package/build/conformity-vocabulary/types.js.map +1 -0
  75. package/build/conformity-vocabulary/validate-conformity-claim.d.ts +26 -0
  76. package/build/conformity-vocabulary/validate-conformity-claim.js +165 -0
  77. package/build/conformity-vocabulary/validate-conformity-claim.js.map +1 -0
  78. package/build/conformity-vocabulary/validate-conformity-claim.test.d.ts +1 -0
  79. package/build/conformity-vocabulary/validate-conformity-claim.test.js +478 -0
  80. package/build/conformity-vocabulary/validate-conformity-claim.test.js.map +1 -0
  81. package/build/http-headers/index.d.ts +5 -0
  82. package/build/http-headers/index.js +6 -0
  83. package/build/http-headers/index.js.map +1 -0
  84. package/build/http-headers/is-safe-header-value.d.ts +10 -0
  85. package/build/http-headers/is-safe-header-value.js +15 -0
  86. package/build/http-headers/is-safe-header-value.js.map +1 -0
  87. package/build/http-headers/is-safe-header-value.test.d.ts +1 -0
  88. package/build/http-headers/is-safe-header-value.test.js +37 -0
  89. package/build/http-headers/is-safe-header-value.test.js.map +1 -0
  90. package/build/http-headers/parse-entity-tag.d.ts +9 -0
  91. package/build/http-headers/parse-entity-tag.js +18 -0
  92. package/build/http-headers/parse-entity-tag.js.map +1 -0
  93. package/build/http-headers/parse-entity-tag.test.d.ts +1 -0
  94. package/build/http-headers/parse-entity-tag.test.js +41 -0
  95. package/build/http-headers/parse-entity-tag.test.js.map +1 -0
  96. package/build/http-headers/parse-imf-date.d.ts +13 -0
  97. package/build/http-headers/parse-imf-date.js +23 -0
  98. package/build/http-headers/parse-imf-date.js.map +1 -0
  99. package/build/http-headers/parse-imf-date.test.d.ts +1 -0
  100. package/build/http-headers/parse-imf-date.test.js +31 -0
  101. package/build/http-headers/parse-imf-date.test.js.map +1 -0
  102. package/build/http-headers/parse-media-type.d.ts +8 -0
  103. package/build/http-headers/parse-media-type.js +21 -0
  104. package/build/http-headers/parse-media-type.js.map +1 -0
  105. package/build/http-headers/parse-media-type.test.d.ts +1 -0
  106. package/build/http-headers/parse-media-type.test.js +39 -0
  107. package/build/http-headers/parse-media-type.test.js.map +1 -0
  108. package/build/http-headers/user-agent.d.ts +35 -0
  109. package/build/http-headers/user-agent.js +45 -0
  110. package/build/http-headers/user-agent.js.map +1 -0
  111. package/build/http-headers/user-agent.test.d.ts +1 -0
  112. package/build/http-headers/user-agent.test.js +27 -0
  113. package/build/http-headers/user-agent.test.js.map +1 -0
  114. package/build/index.d.ts +1 -1
  115. package/build/index.js +1 -1
  116. package/build/index.js.map +1 -1
  117. package/build/loaders/errors.d.ts +21 -0
  118. package/build/loaders/errors.js +45 -0
  119. package/build/loaders/errors.js.map +1 -0
  120. package/build/loaders/index.d.ts +3 -0
  121. package/build/loaders/index.js +4 -0
  122. package/build/loaders/index.js.map +1 -0
  123. package/build/loaders/jsonld-document-loader.d.ts +46 -0
  124. package/build/loaders/jsonld-document-loader.js +34 -0
  125. package/build/loaders/jsonld-document-loader.js.map +1 -0
  126. package/build/loaders/jsonld-document-loader.test.d.ts +1 -0
  127. package/build/loaders/jsonld-document-loader.test.js +71 -0
  128. package/build/loaders/jsonld-document-loader.test.js.map +1 -0
  129. package/build/loaders/schema-loader.d.ts +21 -0
  130. package/build/loaders/schema-loader.js +67 -0
  131. package/build/loaders/schema-loader.js.map +1 -0
  132. package/build/loaders/schema-loader.ssrf.test.d.ts +1 -0
  133. package/build/loaders/schema-loader.ssrf.test.js +55 -0
  134. package/build/loaders/schema-loader.ssrf.test.js.map +1 -0
  135. package/build/loaders/schema-loader.test.d.ts +1 -0
  136. package/build/loaders/schema-loader.test.js +162 -0
  137. package/build/loaders/schema-loader.test.js.map +1 -0
  138. package/build/multibase-digest/multibase-digest.d.ts +23 -0
  139. package/build/multibase-digest/multibase-digest.js +40 -0
  140. package/build/multibase-digest/multibase-digest.js.map +1 -1
  141. package/build/multibase-digest/multibase-digest.test.js +46 -0
  142. package/build/multibase-digest/multibase-digest.test.js.map +1 -1
  143. package/build/node/errors.d.ts +41 -0
  144. package/build/node/errors.js +80 -0
  145. package/build/node/errors.js.map +1 -0
  146. package/build/node/index.d.ts +3 -0
  147. package/build/node/index.js +4 -0
  148. package/build/node/index.js.map +1 -0
  149. package/build/node/is-private-ip.d.ts +41 -0
  150. package/build/node/is-private-ip.js +138 -0
  151. package/build/node/is-private-ip.js.map +1 -0
  152. package/build/node/is-private-ip.test.d.ts +1 -0
  153. package/build/node/is-private-ip.test.js +96 -0
  154. package/build/node/is-private-ip.test.js.map +1 -0
  155. package/build/node/validate-public-url.d.ts +49 -0
  156. package/build/node/validate-public-url.js +94 -0
  157. package/build/node/validate-public-url.js.map +1 -0
  158. package/build/node/validate-public-url.test.d.ts +1 -0
  159. package/build/node/validate-public-url.test.js +177 -0
  160. package/build/node/validate-public-url.test.js.map +1 -0
  161. package/build/resolvers/errors.d.ts +43 -0
  162. package/build/resolvers/errors.js +99 -0
  163. package/build/resolvers/errors.js.map +1 -0
  164. package/build/resolvers/index.d.ts +5 -0
  165. package/build/resolvers/index.js +6 -0
  166. package/build/resolvers/index.js.map +1 -0
  167. package/build/resolvers/resolve-document-if-changed.d.ts +48 -0
  168. package/build/resolvers/resolve-document-if-changed.js +42 -0
  169. package/build/resolvers/resolve-document-if-changed.js.map +1 -0
  170. package/build/resolvers/resolve-document-if-changed.test.d.ts +1 -0
  171. package/build/resolvers/resolve-document-if-changed.test.js +109 -0
  172. package/build/resolvers/resolve-document-if-changed.test.js.map +1 -0
  173. package/build/resolvers/resolve-document.d.ts +86 -0
  174. package/build/resolvers/resolve-document.js +239 -0
  175. package/build/resolvers/resolve-document.js.map +1 -0
  176. package/build/resolvers/resolve-document.test.d.ts +1 -0
  177. package/build/resolvers/resolve-document.test.js +299 -0
  178. package/build/resolvers/resolve-document.test.js.map +1 -0
  179. package/build/resolvers/resolve-json-document.d.ts +40 -0
  180. package/build/resolvers/resolve-json-document.js +42 -0
  181. package/build/resolvers/resolve-json-document.js.map +1 -0
  182. package/build/resolvers/resolve-json-document.test.d.ts +1 -0
  183. package/build/resolvers/resolve-json-document.test.js +61 -0
  184. package/build/resolvers/resolve-json-document.test.js.map +1 -0
  185. package/build/structured-error.d.ts +49 -0
  186. package/build/structured-error.js +17 -0
  187. package/build/structured-error.js.map +1 -0
  188. package/build/structured-error.test.d.ts +1 -0
  189. package/build/structured-error.test.js +112 -0
  190. package/build/structured-error.test.js.map +1 -0
  191. package/build/validation/describe-jsonld-failure.d.ts +50 -0
  192. package/build/validation/describe-jsonld-failure.js +104 -0
  193. package/build/validation/describe-jsonld-failure.js.map +1 -0
  194. package/build/validation/describe-jsonld-failure.test.d.ts +1 -0
  195. package/build/validation/describe-jsonld-failure.test.js +141 -0
  196. package/build/validation/describe-jsonld-failure.test.js.map +1 -0
  197. package/build/validation/errors.d.ts +40 -0
  198. package/build/validation/errors.js +75 -0
  199. package/build/validation/errors.js.map +1 -0
  200. package/build/validation/index.d.ts +4 -0
  201. package/build/validation/index.js +5 -0
  202. package/build/validation/index.js.map +1 -0
  203. package/build/validation/validate-against-schemas.d.ts +22 -0
  204. package/build/validation/validate-against-schemas.js +65 -0
  205. package/build/validation/validate-against-schemas.js.map +1 -0
  206. package/build/validation/validate-against-schemas.test.d.ts +1 -0
  207. package/build/validation/validate-against-schemas.test.js +169 -0
  208. package/build/validation/validate-against-schemas.test.js.map +1 -0
  209. package/build/validation/validate-jsonld.context-cache.test.d.ts +1 -0
  210. package/build/validation/validate-jsonld.context-cache.test.js +32 -0
  211. package/build/validation/validate-jsonld.context-cache.test.js.map +1 -0
  212. package/build/validation/validate-jsonld.d.ts +33 -0
  213. package/build/validation/validate-jsonld.js +99 -0
  214. package/build/validation/validate-jsonld.js.map +1 -0
  215. package/build/validation/validate-jsonld.ssrf.test.d.ts +1 -0
  216. package/build/validation/validate-jsonld.ssrf.test.js +108 -0
  217. package/build/validation/validate-jsonld.ssrf.test.js.map +1 -0
  218. package/build/validation/validate-jsonld.test.d.ts +1 -0
  219. package/build/validation/validate-jsonld.test.js +200 -0
  220. package/build/validation/validate-jsonld.test.js.map +1 -0
  221. package/package.json +77 -11
@@ -0,0 +1,16 @@
1
+ import { isV070OrAbove } from './version';
2
+ describe('isV070OrAbove', () => {
3
+ it.each([
4
+ ['0.7.0', true],
5
+ ['0.7.1', true],
6
+ ['0.8.0', true],
7
+ ['1.0.0', true],
8
+ ['0.6.1', false],
9
+ ['0.6.0', false],
10
+ ['0.5.0', false],
11
+ ['not-a-version', false],
12
+ ])('returns %s -> %s', (version, expected) => {
13
+ expect(isV070OrAbove(version)).toBe(expected);
14
+ });
15
+ });
16
+ //# sourceMappingURL=version.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.test.js","sourceRoot":"","sources":["../../src/artefacts/version.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE1C,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,IAAI,CAAC;QACN,CAAC,OAAO,EAAE,IAAI,CAAC;QACf,CAAC,OAAO,EAAE,IAAI,CAAC;QACf,CAAC,OAAO,EAAE,IAAI,CAAC;QACf,CAAC,OAAO,EAAE,IAAI,CAAC;QACf,CAAC,OAAO,EAAE,KAAK,CAAC;QAChB,CAAC,OAAO,EAAE,KAAK,CAAC;QAChB,CAAC,OAAO,EAAE,KAAK,CAAC;QAChB,CAAC,eAAe,EAAE,KAAK,CAAC;KACzB,CAAC,CAAC,kBAAkB,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;QAC3C,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { TtlCache, TtlCacheOptions } from './ttl-cache.js';
2
+ export declare function createInMemoryTtlCache<T>(options: TtlCacheOptions): TtlCache<T>;
@@ -0,0 +1,76 @@
1
+ export function createInMemoryTtlCache(options) {
2
+ const { ttlMs, maxEntries } = options;
3
+ if (!Number.isFinite(ttlMs) || ttlMs < 0) {
4
+ throw new RangeError(`ttlMs must be a non-negative finite number, got ${ttlMs}.`);
5
+ }
6
+ if (maxEntries !== undefined && (!Number.isInteger(maxEntries) || maxEntries < 1)) {
7
+ throw new RangeError(`maxEntries must be a positive integer when supplied, got ${maxEntries}.`);
8
+ }
9
+ const cache = new Map();
10
+ const inflight = new Map();
11
+ const isFresh = (storedAt) => Date.now() - storedAt < ttlMs;
12
+ // Retention bound: expired entries go first (they are dead weight whatever
13
+ // the cap), then the least recently used live entry. Recency comes from
14
+ // Map insertion order: hits re-insert their key (see get), so iteration
15
+ // order is oldest-touched first.
16
+ const evictForCapacity = () => {
17
+ if (maxEntries === undefined || cache.size < maxEntries)
18
+ return;
19
+ for (const [key, entry] of cache) {
20
+ if (!isFresh(entry.storedAt))
21
+ cache.delete(key);
22
+ }
23
+ while (cache.size >= maxEntries) {
24
+ const oldest = cache.keys().next().value;
25
+ cache.delete(oldest);
26
+ }
27
+ };
28
+ return {
29
+ async get(key, fetcher) {
30
+ if (ttlMs > 0) {
31
+ const cached = cache.get(key);
32
+ if (cached) {
33
+ if (isFresh(cached.storedAt)) {
34
+ // Re-insert so Map iteration order tracks recency for eviction.
35
+ cache.delete(key);
36
+ cache.set(key, cached);
37
+ return cached.value;
38
+ }
39
+ // Expired entries are removed when met rather than lingering until
40
+ // the same key happens to be rewritten.
41
+ cache.delete(key);
42
+ }
43
+ }
44
+ const existing = inflight.get(key);
45
+ if (existing)
46
+ return existing;
47
+ let promise;
48
+ promise = (async () => {
49
+ try {
50
+ const value = await fetcher();
51
+ if (ttlMs > 0 && inflight.get(key) === promise) {
52
+ evictForCapacity();
53
+ cache.set(key, { value, storedAt: Date.now() });
54
+ }
55
+ return value;
56
+ }
57
+ finally {
58
+ if (inflight.get(key) === promise) {
59
+ inflight.delete(key);
60
+ }
61
+ }
62
+ })();
63
+ inflight.set(key, promise);
64
+ return promise;
65
+ },
66
+ async invalidate(key) {
67
+ cache.delete(key);
68
+ inflight.delete(key);
69
+ },
70
+ async clear() {
71
+ cache.clear();
72
+ inflight.clear();
73
+ },
74
+ };
75
+ }
76
+ //# sourceMappingURL=in-memory-ttl-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory-ttl-cache.js","sourceRoot":"","sources":["../../src/cache/in-memory-ttl-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,236 @@
1
+ import { jest } from '@jest/globals';
2
+ import { createInMemoryTtlCache } from './in-memory-ttl-cache.js';
3
+ describe('createInMemoryTtlCache', () => {
4
+ describe('hit / miss', () => {
5
+ it('returns the fetcher result on a miss', async () => {
6
+ const cache = createInMemoryTtlCache({ ttlMs: 1000 });
7
+ await expect(cache.get('a', async () => 'fetched')).resolves.toBe('fetched');
8
+ });
9
+ it('returns the cached value on a subsequent hit within the TTL', async () => {
10
+ const cache = createInMemoryTtlCache({ ttlMs: 1000 });
11
+ const fetcher = jest.fn(async () => 'fetched');
12
+ await cache.get('a', fetcher);
13
+ await cache.get('a', fetcher);
14
+ expect(fetcher).toHaveBeenCalledTimes(1);
15
+ });
16
+ it('refetches after the TTL expires', async () => {
17
+ const realNow = Date.now;
18
+ let now = 1000;
19
+ jest.spyOn(Date, 'now').mockImplementation(() => now);
20
+ try {
21
+ const cache = createInMemoryTtlCache({ ttlMs: 100 });
22
+ const fetcher = jest.fn(async () => 'v');
23
+ await cache.get('a', fetcher);
24
+ now += 101;
25
+ await cache.get('a', fetcher);
26
+ expect(fetcher).toHaveBeenCalledTimes(2);
27
+ }
28
+ finally {
29
+ Date.now = realNow;
30
+ }
31
+ });
32
+ it('treats the TTL boundary strictly: ttlMs - 1 ms is a hit, ttlMs ms is a miss', async () => {
33
+ const realNow = Date.now;
34
+ let now = 1000;
35
+ jest.spyOn(Date, 'now').mockImplementation(() => now);
36
+ try {
37
+ const cache = createInMemoryTtlCache({ ttlMs: 100 });
38
+ const fetcher = jest.fn(async () => 'v');
39
+ await cache.get('a', fetcher);
40
+ now += 99;
41
+ await cache.get('a', fetcher);
42
+ expect(fetcher).toHaveBeenCalledTimes(1);
43
+ now += 1;
44
+ await cache.get('a', fetcher);
45
+ expect(fetcher).toHaveBeenCalledTimes(2);
46
+ }
47
+ finally {
48
+ Date.now = realNow;
49
+ }
50
+ });
51
+ it('treats ttlMs: 0 as a no-cache policy (always misses)', async () => {
52
+ const cache = createInMemoryTtlCache({ ttlMs: 0 });
53
+ const fetcher = jest.fn(async () => 'v');
54
+ await cache.get('a', fetcher);
55
+ await cache.get('a', fetcher);
56
+ expect(fetcher).toHaveBeenCalledTimes(2);
57
+ });
58
+ });
59
+ describe('invalidate during inflight', () => {
60
+ it('does not repopulate the cache when invalidate runs while a fetch is inflight', async () => {
61
+ const cache = createInMemoryTtlCache({ ttlMs: 60_000 });
62
+ let resolveFetcher;
63
+ const fetcher = jest.fn(() => new Promise((r) => {
64
+ resolveFetcher = r;
65
+ }));
66
+ const inflightLoad = cache.get('k', fetcher);
67
+ await cache.invalidate('k');
68
+ resolveFetcher('value-that-should-not-be-cached');
69
+ await inflightLoad;
70
+ const second = await cache.get('k', jest.fn(async () => 'fresh-value'));
71
+ expect(second).toBe('fresh-value');
72
+ });
73
+ });
74
+ describe('options', () => {
75
+ it('rejects negative ttlMs', () => {
76
+ expect(() => createInMemoryTtlCache({ ttlMs: -1 })).toThrow(RangeError);
77
+ });
78
+ it('rejects non-finite ttlMs', () => {
79
+ expect(() => createInMemoryTtlCache({ ttlMs: NaN })).toThrow(RangeError);
80
+ expect(() => createInMemoryTtlCache({ ttlMs: Infinity })).toThrow(RangeError);
81
+ });
82
+ });
83
+ describe('retention bound (maxEntries)', () => {
84
+ it('rejects a non-positive or non-integer maxEntries', () => {
85
+ expect(() => createInMemoryTtlCache({ ttlMs: 1000, maxEntries: 0 })).toThrow(RangeError);
86
+ expect(() => createInMemoryTtlCache({ ttlMs: 1000, maxEntries: 1.5 })).toThrow(RangeError);
87
+ expect(() => createInMemoryTtlCache({ ttlMs: 1000, maxEntries: -1 })).toThrow(RangeError);
88
+ });
89
+ it('evicts the least recently used entry when the cap is reached', async () => {
90
+ const cache = createInMemoryTtlCache({ ttlMs: 60_000, maxEntries: 2 });
91
+ const fetches = [];
92
+ const fetcher = (v) => async () => {
93
+ fetches.push(v);
94
+ return v;
95
+ };
96
+ await cache.get('a', fetcher('a'));
97
+ await cache.get('b', fetcher('b'));
98
+ await cache.get('a', fetcher('a-refetch')); // touch a, so b is now least recent
99
+ await cache.get('c', fetcher('c')); // cap reached: evicts b
100
+ expect(await cache.get('a', fetcher('a-refetch'))).toBe('a'); // still cached
101
+ expect(await cache.get('b', fetcher('b-refetch'))).toBe('b-refetch'); // evicted, refetched
102
+ expect(fetches).toEqual(['a', 'b', 'c', 'b-refetch']);
103
+ });
104
+ it('evicts expired entries before evicting live ones', async () => {
105
+ const realNow = Date.now;
106
+ let now = 1_000_000;
107
+ Date.now = () => now;
108
+ try {
109
+ const cache = createInMemoryTtlCache({ ttlMs: 1000, maxEntries: 2 });
110
+ await cache.get('old', async () => 'old');
111
+ now += 2000; // 'old' expires
112
+ await cache.get('live', async () => 'live');
113
+ await cache.get('new', async () => 'new'); // cap: removes expired 'old', keeps 'live'
114
+ const fetches = [];
115
+ expect(await cache.get('live', async () => {
116
+ fetches.push('live-refetch');
117
+ return 'live-refetch';
118
+ })).toBe('live');
119
+ expect(fetches).toEqual([]);
120
+ }
121
+ finally {
122
+ Date.now = realNow;
123
+ }
124
+ });
125
+ it('removes an expired entry when it is met, even with no cap configured', async () => {
126
+ const realNow = Date.now;
127
+ let now = 1_000_000;
128
+ Date.now = () => now;
129
+ try {
130
+ const cache = createInMemoryTtlCache({ ttlMs: 1000 });
131
+ await cache.get('k', async () => 'v1');
132
+ now += 2000;
133
+ // Expired: refetches, and the stale entry is deleted rather than
134
+ // lingering until this key happens to be rewritten.
135
+ await expect(cache.get('k', async () => 'v2')).resolves.toBe('v2');
136
+ expect(await cache.get('k', async () => 'v3')).toBe('v2');
137
+ }
138
+ finally {
139
+ Date.now = realNow;
140
+ }
141
+ });
142
+ });
143
+ describe('deduplication', () => {
144
+ it('deduplicates concurrent fetches for the same key', async () => {
145
+ const cache = createInMemoryTtlCache({ ttlMs: 1000 });
146
+ let resolveFetcher;
147
+ const fetcher = jest.fn(() => new Promise((r) => {
148
+ resolveFetcher = r;
149
+ }));
150
+ const a = cache.get('k', fetcher);
151
+ const b = cache.get('k', fetcher);
152
+ resolveFetcher('done');
153
+ await expect(a).resolves.toBe('done');
154
+ await expect(b).resolves.toBe('done');
155
+ expect(fetcher).toHaveBeenCalledTimes(1);
156
+ });
157
+ it('runs fetcher independently for distinct keys', async () => {
158
+ const cache = createInMemoryTtlCache({ ttlMs: 1000 });
159
+ const fetcher = jest.fn(async () => 'v');
160
+ await cache.get('a', fetcher);
161
+ await cache.get('b', fetcher);
162
+ expect(fetcher).toHaveBeenCalledTimes(2);
163
+ });
164
+ });
165
+ describe('errors', () => {
166
+ it('propagates fetcher rejections without caching the failure', async () => {
167
+ const cache = createInMemoryTtlCache({ ttlMs: 1000 });
168
+ let attempt = 0;
169
+ const fetcher = jest.fn(async () => {
170
+ attempt += 1;
171
+ if (attempt === 1)
172
+ throw new Error('boom');
173
+ return 'ok';
174
+ });
175
+ await expect(cache.get('a', fetcher)).rejects.toThrow('boom');
176
+ await expect(cache.get('a', fetcher)).resolves.toBe('ok');
177
+ expect(fetcher).toHaveBeenCalledTimes(2);
178
+ });
179
+ it('fans the same rejection out to every concurrent caller and retries on the next call', async () => {
180
+ const cache = createInMemoryTtlCache({ ttlMs: 1000 });
181
+ let rejectFetcher;
182
+ const fetcher = jest.fn(() => new Promise((_resolve, reject) => {
183
+ rejectFetcher = reject;
184
+ }));
185
+ const a = cache.get('k', fetcher);
186
+ const b = cache.get('k', fetcher);
187
+ const sharedError = new Error('shared boom');
188
+ rejectFetcher(sharedError);
189
+ const aErr = await a.catch((e) => e);
190
+ const bErr = await b.catch((e) => e);
191
+ expect(aErr).toBe(sharedError);
192
+ expect(bErr).toBe(sharedError);
193
+ expect(fetcher).toHaveBeenCalledTimes(1);
194
+ const c = await cache.get('k', jest.fn(async () => 'ok'));
195
+ expect(c).toBe('ok');
196
+ });
197
+ it('clears inflight on rejection so subsequent callers retry', async () => {
198
+ const cache = createInMemoryTtlCache({ ttlMs: 1000 });
199
+ let resolveFetcher;
200
+ let rejectFetcher;
201
+ const fetcher = jest.fn(() => new Promise((r, rej) => {
202
+ resolveFetcher = r;
203
+ rejectFetcher = rej;
204
+ }));
205
+ const first = cache.get('k', fetcher);
206
+ rejectFetcher(new Error('first fail'));
207
+ await expect(first).rejects.toThrow('first fail');
208
+ const second = cache.get('k', fetcher);
209
+ resolveFetcher('second ok');
210
+ await expect(second).resolves.toBe('second ok');
211
+ expect(fetcher).toHaveBeenCalledTimes(2);
212
+ });
213
+ });
214
+ describe('invalidate / clear', () => {
215
+ it('invalidate removes a single key without touching others', async () => {
216
+ const cache = createInMemoryTtlCache({ ttlMs: 1000 });
217
+ const fetcher = jest.fn(async () => 'v');
218
+ await cache.get('a', fetcher);
219
+ await cache.get('b', fetcher);
220
+ await cache.invalidate('a');
221
+ await cache.get('a', fetcher);
222
+ await cache.get('b', fetcher);
223
+ expect(fetcher).toHaveBeenCalledTimes(3);
224
+ });
225
+ it('clear removes every cached value', async () => {
226
+ const cache = createInMemoryTtlCache({ ttlMs: 1000 });
227
+ const fetcher = jest.fn(async () => 'v');
228
+ await cache.get('a', fetcher);
229
+ await cache.get('b', fetcher);
230
+ await cache.clear();
231
+ await cache.get('a', fetcher);
232
+ expect(fetcher).toHaveBeenCalledTimes(3);
233
+ });
234
+ });
235
+ });
236
+ //# sourceMappingURL=in-memory-ttl-cache.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory-ttl-cache.test.js","sourceRoot":"","sources":["../../src/cache/in-memory-ttl-cache.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export type { TtlCache, TtlCacheOptions } from './ttl-cache.js';
2
+ export { createInMemoryTtlCache } from './in-memory-ttl-cache.js';
@@ -0,0 +1,2 @@
1
+ export { createInMemoryTtlCache } from './in-memory-ttl-cache.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,22 @@
1
+ export interface TtlCacheOptions {
2
+ /** TTL in ms. `0` disables caching. */
3
+ ttlMs: number;
4
+ /**
5
+ * Maximum number of stored entries. When a write would exceed it, expired
6
+ * entries are removed first, then the least recently used live entry is
7
+ * evicted. Omit for no bound (suitable only when keys come from trusted
8
+ * configuration; caller-controlled keys need a cap so a stream of unique
9
+ * keys cannot grow process memory without limit).
10
+ */
11
+ maxEntries?: number;
12
+ }
13
+ export interface TtlCache<T> {
14
+ /**
15
+ * Returns the cached value for `key` if fresh; otherwise invokes
16
+ * `fetcher`, stores its result, and returns it. Implementations may
17
+ * deduplicate concurrent misses; rejected fetches are not cached.
18
+ */
19
+ get(key: string, fetcher: () => Promise<T>): Promise<T>;
20
+ invalidate(key: string): Promise<void>;
21
+ clear(): Promise<void>;
22
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ttl-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ttl-cache.js","sourceRoot":"","sources":["../../src/cache/ttl-cache.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Returns `value` if it is a non-empty string, otherwise `undefined`.
3
+ * Useful inside parsers that emit a structured failure separately when a
4
+ * required field is missing or malformed, so the type check and the
5
+ * failure-emission policy stay decoupled.
6
+ */
7
+ export declare function asNonEmptyString(value: unknown): string | undefined;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Returns `value` if it is a non-empty string, otherwise `undefined`.
3
+ * Useful inside parsers that emit a structured failure separately when a
4
+ * required field is missing or malformed, so the type check and the
5
+ * failure-emission policy stay decoupled.
6
+ */
7
+ export function asNonEmptyString(value) {
8
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
9
+ }
10
+ //# sourceMappingURL=as-non-empty-string.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"as-non-empty-string.js","sourceRoot":"","sources":["../../src/common/as-non-empty-string.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3E,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import { asNonEmptyString } from './as-non-empty-string.js';
2
+ describe('asNonEmptyString', () => {
3
+ it('returns the value for a non-empty string', () => {
4
+ expect(asNonEmptyString('foo')).toBe('foo');
5
+ expect(asNonEmptyString(' ')).toBe(' ');
6
+ expect(asNonEmptyString('0')).toBe('0');
7
+ });
8
+ it('returns undefined for the empty string', () => {
9
+ expect(asNonEmptyString('')).toBeUndefined();
10
+ });
11
+ it.each([
12
+ ['number', 0],
13
+ ['number (non-zero)', 42],
14
+ ['null', null],
15
+ ['undefined', undefined],
16
+ ['boolean true', true],
17
+ ['boolean false', false],
18
+ ['object', {}],
19
+ ['array', ['a']],
20
+ ['NaN', NaN],
21
+ ])('returns undefined for %s', (_label, value) => {
22
+ expect(asNonEmptyString(value)).toBeUndefined();
23
+ });
24
+ });
25
+ //# sourceMappingURL=as-non-empty-string.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"as-non-empty-string.test.js","sourceRoot":"","sources":["../../src/common/as-non-empty-string.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN,CAAC,QAAQ,EAAE,CAAC,CAAC;QACb,CAAC,mBAAmB,EAAE,EAAE,CAAC;QACzB,CAAC,MAAM,EAAE,IAAI,CAAC;QACd,CAAC,WAAW,EAAE,SAAS,CAAC;QACxB,CAAC,cAAc,EAAE,IAAI,CAAC;QACtB,CAAC,eAAe,EAAE,KAAK,CAAC;QACxB,CAAC,QAAQ,EAAE,EAAE,CAAC;QACd,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC,KAAK,EAAE,GAAG,CAAC;KACb,CAAC,CAAC,0BAA0B,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QAC/C,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ValidationFailure } from '../structured-error.js';
2
+ /**
3
+ * Returns a `requireString(value, fieldName, pointer, failures)` helper
4
+ * pre-bound to a structured-failure `code`. When `value` is a non-empty
5
+ * string, returns it; otherwise pushes a {@link ValidationFailure} onto
6
+ * `failures` and returns `undefined`.
7
+ *
8
+ * Each parser binds the factory once per file with its sub-entry's
9
+ * missing-required-field code, keeping per-call sites unaware of the code
10
+ * namespace.
11
+ */
12
+ export declare function makeRequireString(code: string): (value: unknown, fieldName: string, pointer: string, failures: ValidationFailure[]) => string | undefined;
@@ -0,0 +1,27 @@
1
+ import { asNonEmptyString } from './as-non-empty-string.js';
2
+ /**
3
+ * Returns a `requireString(value, fieldName, pointer, failures)` helper
4
+ * pre-bound to a structured-failure `code`. When `value` is a non-empty
5
+ * string, returns it; otherwise pushes a {@link ValidationFailure} onto
6
+ * `failures` and returns `undefined`.
7
+ *
8
+ * Each parser binds the factory once per file with its sub-entry's
9
+ * missing-required-field code, keeping per-call sites unaware of the code
10
+ * namespace.
11
+ */
12
+ export function makeRequireString(code) {
13
+ return function requireString(value, fieldName, pointer, failures) {
14
+ const parsed = asNonEmptyString(value);
15
+ if (parsed !== undefined)
16
+ return parsed;
17
+ failures.push({
18
+ code,
19
+ message: `${fieldName} is required and must be a non-empty string.`,
20
+ received: value === undefined ? 'undefined' : value === null ? 'null' : value === '' ? 'empty string' : typeof value,
21
+ expected: 'non-empty string',
22
+ pointer,
23
+ });
24
+ return undefined;
25
+ };
26
+ }
27
+ //# sourceMappingURL=require-string.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-string.js","sourceRoot":"","sources":["../../src/common/require-string.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,SAAS,aAAa,CAC3B,KAAc,EACd,SAAiB,EACjB,OAAe,EACf,QAA6B;QAE7B,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QACxC,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI;YACJ,OAAO,EAAE,GAAG,SAAS,8CAA8C;YACnE,QAAQ,EACN,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,KAAK;YAC5G,QAAQ,EAAE,kBAAkB;YAC5B,OAAO;SACR,CAAC,CAAC;QACH,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,53 @@
1
+ import { makeRequireString } from './require-string.js';
2
+ const CODE = 'test.missing-required-field';
3
+ describe('makeRequireString', () => {
4
+ let failures;
5
+ const requireString = makeRequireString(CODE);
6
+ beforeEach(() => {
7
+ failures = [];
8
+ });
9
+ it('returns the value when it is a non-empty string', () => {
10
+ expect(requireString('foo', 'field', '/pointer', failures)).toBe('foo');
11
+ expect(failures).toEqual([]);
12
+ });
13
+ it('returns undefined and pushes a failure when the value is undefined', () => {
14
+ expect(requireString(undefined, 'scheme.id', '/id', failures)).toBeUndefined();
15
+ expect(failures).toEqual([
16
+ expect.objectContaining({
17
+ code: CODE,
18
+ pointer: '/id',
19
+ received: 'undefined',
20
+ expected: 'non-empty string',
21
+ }),
22
+ ]);
23
+ });
24
+ it('returns undefined and pushes a failure when the value is the empty string (discriminated from typeof "string")', () => {
25
+ expect(requireString('', 'scheme.name', '/name', failures)).toBeUndefined();
26
+ expect(failures[0]).toMatchObject({ code: CODE, pointer: '/name', received: 'empty string' });
27
+ });
28
+ it.each([
29
+ ['null', null, 'null'],
30
+ ['number', 42, 'number'],
31
+ ['boolean', true, 'boolean'],
32
+ ['object', {}, 'object'],
33
+ ['array', [], 'object'],
34
+ ])('returns undefined and pushes a failure when the value is %s', (_label, value, expectedReceived) => {
35
+ expect(requireString(value, 'field', '/p', failures)).toBeUndefined();
36
+ expect(failures[0]).toMatchObject({ code: CODE, received: expectedReceived });
37
+ });
38
+ it('uses the field name in the failure message', () => {
39
+ requireString(undefined, 'profile.criterion[2].id', '/profile/criterion/2/id', failures);
40
+ expect(failures[0].message).toContain('profile.criterion[2].id');
41
+ });
42
+ it('binds the code once per factory call (different codes do not bleed across instances)', () => {
43
+ const a = makeRequireString('foo.missing');
44
+ const b = makeRequireString('bar.missing');
45
+ const failuresA = [];
46
+ const failuresB = [];
47
+ a(undefined, 'x', '/x', failuresA);
48
+ b(undefined, 'y', '/y', failuresB);
49
+ expect(failuresA[0].code).toBe('foo.missing');
50
+ expect(failuresB[0].code).toBe('bar.missing');
51
+ });
52
+ });
53
+ //# sourceMappingURL=require-string.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-string.test.js","sourceRoot":"","sources":["../../src/common/require-string.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export declare const ConformityWarningCode: {
2
+ readonly SchemeNotFound: "conformity-scheme.not-found";
3
+ readonly ProfileNotFound: "conformity-profile.not-found";
4
+ readonly ProfileNotSpecified: "conformity-profile.not-specified";
5
+ readonly CriterionNotInProfile: "conformity-criterion.not-in-profile";
6
+ readonly CriterionMissing: "conformity-criterion.missing";
7
+ readonly CriterionTopicMismatch: "conformity-criterion.topic-mismatch";
8
+ readonly AssessmentTopicMismatch: "conformity-assessment.topic-mismatch";
9
+ };
10
+ export type ConformityWarningCode = (typeof ConformityWarningCode)[keyof typeof ConformityWarningCode];
@@ -0,0 +1,10 @@
1
+ export const ConformityWarningCode = {
2
+ SchemeNotFound: 'conformity-scheme.not-found',
3
+ ProfileNotFound: 'conformity-profile.not-found',
4
+ ProfileNotSpecified: 'conformity-profile.not-specified',
5
+ CriterionNotInProfile: 'conformity-criterion.not-in-profile',
6
+ CriterionMissing: 'conformity-criterion.missing',
7
+ CriterionTopicMismatch: 'conformity-criterion.topic-mismatch',
8
+ AssessmentTopicMismatch: 'conformity-assessment.topic-mismatch',
9
+ };
10
+ //# sourceMappingURL=codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codes.js","sourceRoot":"","sources":["../../src/conformity-vocabulary/codes.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,cAAc,EAAE,6BAA6B;IAC7C,eAAe,EAAE,8BAA8B;IAC/C,mBAAmB,EAAE,kCAAkC;IACvD,qBAAqB,EAAE,qCAAqC;IAC5D,gBAAgB,EAAE,8BAA8B;IAChD,sBAAsB,EAAE,qCAAqC;IAC7D,uBAAuB,EAAE,sCAAsC;CACvD,CAAC"}