Skip to content

Commit a7e9deb

Browse files
committed
More type refactoring. Maybe this one will work
1 parent eecdbf0 commit a7e9deb

15 files changed

+151
-291
lines changed

src/hyperjump/embedded.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { fromJref } from "../jref/index.js";
66
import { toJson } from "../json/jsonast-util.js";
77

88
/**
9-
* @import { JrefJrefNode } from "../jref/jref-ast.js"
9+
* @import { JrefNode } from "../jref/jref-ast.js"
1010
*/
1111

1212

@@ -20,7 +20,7 @@ describe("JSON Browser", () => {
2020
/**
2121
* @typedef {{
2222
* type: "embedded-document";
23-
* children: JrefJrefNode[];
23+
* children: JrefNode[];
2424
* uri: string;
2525
* fragmentKind: "json-pointer";
2626
* embedded?: Record<string, EmbeddedDocumentNode>;

src/hyperjump/hyperjump.d.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import type { JsonNode } from "../json/jsonast.d.ts";
2-
import type { JrefJrefNode } from "../jref/jref-ast.d.ts";
1+
import type { JrefNode } from "../jref/jref-ast.js";
32
import type { UriSchemePlugin } from "./uri-schemes/uri-scheme-plugin.d.ts";
43
import type { DocumentNode, MediaTypePlugin } from "./media-types/media-type-plugin.d.ts";
54
import type { jsonObjectHas, jsonObjectKeys, jsonValue } from "../json/jsonast-util.js";
@@ -11,7 +10,9 @@ export type GetOptions = {
1110
referencedFrom?: string;
1211
};
1312

14-
export class Hyperjump<T extends JrefNode<{}> = JrefJrefNode> {
13+
type UnionIncludes<T, U> = U extends T ? T : never;
14+
15+
export class Hyperjump<T extends UnionIncludes<U, JrefNode> = JrefNode> {
1516
constructor(config?: HyperjumpConfig);
1617

1718
/**
@@ -29,7 +30,7 @@ export class Hyperjump<T extends JrefNode<{}> = JrefJrefNode> {
2930
* @throws {@link RetrievalError}
3031
* @throws {@link json.JsonPointerError}
3132
*/
32-
get: (uri: string, options?: GetOptions) => Promise<JsonNode<T>>;
33+
get: (uri: string, options?: GetOptions) => Promise<T>;
3334

3435
/**
3536
* Add support for a
@@ -71,7 +72,7 @@ export class Hyperjump<T extends JrefNode<{}> = JrefJrefNode> {
7172
* {@link hyperjump.JsonMediaTypePlugin | `JSON`} media types are enabled by
7273
* default.
7374
*/
74-
addMediaTypePlugin: <A extends DocumentNode<T>>(plugin: MediaTypePlugin<A>) => void;
75+
addMediaTypePlugin: <A extends DocumentNode>(plugin: MediaTypePlugin<A>) => void;
7576

7677
/**
7778
* This is mostly useful for disabling a scheme that's enabled by default.
@@ -93,27 +94,27 @@ export class Hyperjump<T extends JrefNode<{}> = JrefJrefNode> {
9394
* This is like indexing into an object or array. It will follow any
9495
* references it encounters so it always returns a JSON compatible value.
9596
*/
96-
step: (key: string, node: JsonNode<T>) => Promise<JsonNode<T>>;
97+
step: (key: string, node: T) => Promise<T>;
9798

9899
/**
99100
* Iterate over an array node. It will follow any references it encounters so
100101
* it always yields JSON compatible values.
101102
*/
102-
iter: (node: JsonNode<T>) => AsyncGenerator<JsonNode<T>, void, unknown>;
103+
iter: (node: T) => AsyncGenerator<T, void, unknown>;
103104

104105
keys: typeof jsonObjectKeys;
105106

106107
/**
107108
* Iterate over the values of an object. It will follow any references it
108109
* encounters so it always yields JSON compatible values.
109110
*/
110-
values: (node: JsonNode<T>) => AsyncGenerator<JsonNode<T>, void, unknown>;
111+
values: (node: T) => AsyncGenerator<T, void, unknown>;
111112

112113
/**
113114
* Iterate over key/value pairs of an object. It will follow any references it
114115
* encounters so it always yields JSON compatible values.
115116
*/
116-
entries: (node: JsonNode<T>) => AsyncGenerator<[string, JsonNode<T>], void, unknown>;
117+
entries: (node: T) => AsyncGenerator<[string, T], void, unknown>;
117118
}
118119

119120
export class RetrievalError extends Error {

src/hyperjump/hyperjump.js

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import { jsonObjectHas, jsonObjectKeys, jsonValue, pointerGet, pointerStep } fro
99
import { mimeMatch } from "./utilities.js";
1010

1111
/**
12-
* @import { JrefJrefNode, JrefNode } from "../jref/jref-ast.js"
13-
* @import { JsonNode } from "../json/jsonast.js"
12+
* @import { JrefNode } from "../jref/jref-ast.js"
1413
* @import { UriSchemePlugin } from "./uri-schemes/uri-scheme-plugin.js"
1514
* @import { DocumentNode, MediaTypePlugin } from "./media-types/media-type-plugin.js"
1615
* @import * as API from "./hyperjump.d.ts"
@@ -21,20 +20,19 @@ import { mimeMatch } from "./utilities.js";
2120
// TODO: Support filters
2221

2322
/**
24-
* @template {JrefNode<unknown>} [T=JrefJrefNode]
25-
* @implements API.Hyperjump<T>
23+
* @implements API.Hyperjump<JrefNode>
2624
*/
2725
export class Hyperjump {
2826
// TODO: Add config to enable schemes and media types
2927
#config;
3028

31-
/** @type Record<string, DocumentNode<T>> */
29+
/** @type Record<string, DocumentNode> */
3230
#cache;
3331

3432
/** @type Record<string, UriSchemePlugin> */
3533
#uriSchemePlugins;
3634

37-
/** @type Record<string, MediaTypePlugin<DocumentNode<T>>> */
35+
/** @type Record<string, MediaTypePlugin<DocumentNode>> */
3836
#mediaTypePlugins;
3937

4038
/** @type API.GetOptions */
@@ -62,7 +60,7 @@ export class Hyperjump {
6260
this.addMediaTypePlugin(new JsonMediaTypePlugin());
6361
}
6462

65-
/** @type API.Hyperjump<T>["get"] */
63+
/** @type API.Hyperjump<JrefNode>["get"] */
6664
async get(uri, options = this.#defaultGetOptions) {
6765
uri = resolveIri(uri, contextUri());
6866
const id = toAbsoluteIri(uri);
@@ -95,28 +93,28 @@ export class Hyperjump {
9593
return await this.#followReferences(node);
9694
}
9795

98-
/** @type (node: JrefNode<T>) => Promise<JsonNode<T>> */
96+
/** @type (node: JrefNode) => Promise<JrefNode> */
9997
async #followReferences(node) {
100-
if (node.jrefType === "reference") {
98+
if (node.type === "reference") {
10199
return this.get(node.href, { referencedFrom: toAbsoluteIri(node.location) });
102100
} else {
103-
return /** @type JsonNode<T> */ (node);
101+
return node;
104102
}
105103
}
106104

107-
/** @type API.Hyperjump<T>["addUriSchemePlugin"] */
105+
/** @type API.Hyperjump<JrefNode>["addUriSchemePlugin"] */
108106
addUriSchemePlugin(plugin) {
109107
for (const scheme of plugin.schemes) {
110108
this.#uriSchemePlugins[scheme] = plugin;
111109
}
112110
}
113111

114-
/** @type API.Hyperjump<T>["removeUriSchemePlugin"] */
112+
/** @type API.Hyperjump<JrefNode>["removeUriSchemePlugin"] */
115113
removeUriSchemePlugin(scheme) {
116114
delete this.#uriSchemePlugins[scheme];
117115
}
118116

119-
/** @type API.Hyperjump<T>["retrieve"] */
117+
/** @type API.Hyperjump<JrefNode>["retrieve"] */
120118
async retrieve(uri, options) {
121119
const { scheme } = parseIri(uri);
122120

@@ -127,7 +125,7 @@ export class Hyperjump {
127125
return this.#uriSchemePlugins[scheme].retrieve(uri, options);
128126
}
129127

130-
/** @type API.Hyperjump<T>["acceptableMediaTypes"] */
128+
/** @type API.Hyperjump<JrefNode>["acceptableMediaTypes"] */
131129
acceptableMediaTypes() {
132130
let accept = "";
133131

@@ -151,7 +149,7 @@ export class Hyperjump {
151149
return accept;
152150
}
153151

154-
/** @type API.Hyperjump<T>["getMediaType"] */
152+
/** @type API.Hyperjump<JrefNode>["getMediaType"] */
155153
getMediaType(uri) {
156154
for (const contentType in this.#mediaTypePlugins) {
157155
for (const extension of this.#mediaTypePlugins[contentType].extensions) {
@@ -166,22 +164,22 @@ export class Hyperjump {
166164
throw new UnknownMediaTypeError(`The media type of the file at '${uri}' could not be determined. Use the 'addMediaTypePlugin' function to add support for this media type.`);
167165
}
168166

169-
/** @type API.Hyperjump<T>["addMediaTypePlugin"] */
167+
/** @type API.Hyperjump<JrefNode>["addMediaTypePlugin"] */
170168
addMediaTypePlugin(plugin) {
171169
this.#mediaTypePlugins[plugin.mediaType] = plugin;
172170
}
173171

174-
/** @type API.Hyperjump<T>["removeMediaTypePlugin"] */
172+
/** @type API.Hyperjump<JrefNode>["removeMediaTypePlugin"] */
175173
removeMediaTypePlugin(contentType) {
176174
delete this.#mediaTypePlugins[contentType];
177175
}
178176

179-
/** @type API.Hyperjump<T>["setMediaTypeQuality"] */
177+
/** @type API.Hyperjump<JrefNode>["setMediaTypeQuality"] */
180178
setMediaTypeQuality(contentType, quality) {
181179
this.#mediaTypePlugins[contentType].quality = quality;
182180
}
183181

184-
/** @type (response: Response) => Promise<DocumentNode<T>> */
182+
/** @type (response: Response) => Promise<DocumentNode> */
185183
#parseResponse(response) {
186184
const contentTypeText = response.headers.get("content-type");
187185
if (contentTypeText === null) {
@@ -201,12 +199,12 @@ export class Hyperjump {
201199
value = jsonValue;
202200
has = jsonObjectHas;
203201

204-
/** @type API.Hyperjump<T>["step"] */
202+
/** @type API.Hyperjump<JrefNode>["step"] */
205203
async step(key, node) {
206204
return await this.#followReferences(pointerStep(key, node));
207205
}
208206

209-
/** @type API.Hyperjump<T>["iter"] */
207+
/** @type API.Hyperjump<JrefNode>["iter"] */
210208
async* iter(node) {
211209
if (node.jsonType === "array") {
212210
for (const itemNode of node.children) {
@@ -217,7 +215,7 @@ export class Hyperjump {
217215

218216
keys = jsonObjectKeys;
219217

220-
/** @type API.Hyperjump<T>["values"] */
218+
/** @type API.Hyperjump<JrefNode>["values"] */
221219
async* values(node) {
222220
if (node.jsonType === "object") {
223221
for (const propertyNode of node.children) {
@@ -226,7 +224,7 @@ export class Hyperjump {
226224
}
227225
}
228226

229-
/** @type API.Hyperjump<T>["entries"] */
227+
/** @type API.Hyperjump<JrefNode>["entries"] */
230228
async* entries(node) {
231229
if (node.jsonType === "object") {
232230
for (const propertyNode of node.children) {

src/hyperjump/media-types/media-type-plugin.d.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
export type DocumentNode<A> = {
1+
import type { JrefNode } from "../../jref/jref-ast.js";
2+
3+
export type DocumentNode = {
24
type: string;
3-
children: A[];
5+
children: JrefNode[];
46
uri?: string;
5-
embedded?: Record<string, DocumentNode<A>>;
7+
embedded?: Record<string, DocumentNode>;
68
anchors?: Record<string, string>;
79
fragmentKind?: string;
810
};
911

1012
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
11-
export interface MediaTypePlugin<T extends DocumentNode<unknown>> {
13+
export interface MediaTypePlugin<T extends DocumentNode> {
1214
mediaType: string;
1315
/**
1416
* Extensions start with `.` (Example: `.jref`).

src/hyperjump/node-functions.test.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import { MockAgent, setGlobalDispatcher } from "undici";
33
import { Hyperjump } from "./index.js";
44

55
/**
6-
* @import { JsonNode } from "../json/index.js"
7-
* @import { JrefJrefNode } from "../jref/index.js"
6+
* @import { JrefNode } from "../jref/index.js"
87
*/
98

109

@@ -26,7 +25,7 @@ describe("JSON Browser", () => {
2625
describe("object has property", () => {
2726
const hyperjump = new Hyperjump();
2827

29-
/** @type JsonNode<JrefJrefNode> */
28+
/** @type JrefNode */
3029
let node;
3130

3231
beforeEach(async () => {

src/jref/jref-ast.d.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
import type { Data } from "unist";
22
import type { JsonNode } from "../json/jsonast.d.ts";
33

4-
export type JrefNode<A> = JsonNode<A & (
5-
{
6-
jrefType: "json";
7-
} | {
8-
jrefType: "reference";
9-
href: string;
10-
}
11-
)>;
12-
13-
export type JrefJrefNode = JrefNode<{ type: "jref" }>;
4+
export type JrefNode = JsonNode<{
5+
type: "json";
6+
} | {
7+
type: "reference";
8+
href: string;
9+
}>;
1410

1511
export type JrefDocumentNode = {
1612
type: "jref-document";
17-
children: JrefNode<{}>[];
13+
children: JrefNode[];
1814
uri: string;
1915
fragmentKind: "json-pointer";
2016
data?: Data;

src/jref/jref-parse.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { Plugin } from "unified";
2-
import { JrefDocumentNode, JrefJrefNode } from "./jref-ast.d.ts";
2+
import { JrefDocumentNode, JrefNode } from "./jref-ast.d.ts";
33
import { Reviver } from "./jref-util.js";
44

55

66
export type JrefParseOptions = {
7-
reviver?: Reviver<JrefJrefNode, JrefJrefNode>;
7+
reviver?: Reviver<JrefNode | undefined>;
88
};
99

1010
/**

src/jref/jref-util.d.ts

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,9 @@
1-
import type {
2-
JsonArrayNode,
3-
JsonBooleanNode,
4-
JsonNullNode,
5-
JsonNumberNode,
6-
JsonObjectNode,
7-
JsonStringNode
8-
} from "../json/jsonast.js";
91
import type { JrefNode } from "./jref-ast.d.ts";
102

11-
export type ParsedJrefNode<A> = {
12-
type: "jref";
13-
} & (
14-
{
15-
jrefType: "json";
16-
} | {
17-
jrefType: "reference";
18-
href: string;
19-
}
20-
) & (
21-
JsonObjectNode<JrefNode<A>>
22-
| JsonArrayNode<JrefNode<A>>
23-
| JsonStringNode
24-
| JsonNumberNode
25-
| JsonBooleanNode
26-
| JsonNullNode
27-
);
28-
29-
export type Reviver<A, R extends JrefNode<A> | undefined> = (node: ParsedJrefNode<A>, key?: string) => R;
3+
export type Reviver<A extends JrefNode | undefined> = (node: JrefNode, key?: string) => A;
304

315
/**
326
* Parse a JRef string into a JRef AST. Includes a reviver option similar to
337
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse | JSON.parse}.
348
*/
35-
export const fromJref: <A = { type: "jref" }, R = JrefNode<A>>(json: string, uri: string, reviver?: Reviver<A, R>) => R;
9+
export const fromJref: <A extends JrefNode | undefined = JrefNode>(json: string, uri: string, reviver?: Reviver<A>) => A;

0 commit comments

Comments
 (0)