Skip to content

Commit 580696c

Browse files
fix: implement getAPIUrls (#39)
* fix: implement `getAPIUrls` * fix: move handler back where they belong * chore(jsdoc): use better naming and document methods
1 parent 91489cf commit 580696c

File tree

15 files changed

+172
-39
lines changed

15 files changed

+172
-39
lines changed

src/index.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,6 @@ const nameSelector = (segs) => {
5757
return literals.join('-');
5858
};
5959

60-
/**
61-
* Routing table.
62-
*/
6360
export const router = new Router(nameSelector)
6461
.add('/auth/*', auth)
6562
.add('/discover', discover)
@@ -105,7 +102,7 @@ async function run(request, context) {
105102
if (!handler) {
106103
return new Response('', { status: 404 });
107104
}
108-
const info = RequestInfo.create(request, variables);
105+
const info = RequestInfo.create(request, router, variables);
109106
if (info.method === 'OPTIONS') {
110107
return new Response('', {
111108
status: 204,

src/live/status.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export default async function liveStatus(context, info) {
3636
webPath: info.webPath,
3737
resourcePath: info.resourcePath,
3838
live,
39-
// TODO links: getAPIUrls(ctx, info, 'status', 'preview', 'live', 'code'),
39+
links: info.getAPIUrls('status', 'preview', 'live', 'code'),
4040
};
4141

4242
return new Response(JSON.stringify(resp, null, 2), {

src/preview/status.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export default async function previewStatus(context, info) {
3636
webPath: info.webPath,
3737
resourcePath: info.resourcePath,
3838
preview,
39-
// TODO links: getAPIUrls(context, info, 'status', 'preview', 'live', 'code'),
39+
links: info.getAPIUrls('status', 'preview', 'live', 'code'),
4040
};
4141

4242
return new Response(JSON.stringify(resp, null, 2), {

src/router/node.js

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
* OF ANY KIND, either express or implied. See the License for the specific language
1010
* governing permissions and limitations under the License.
1111
*/
12+
const NodeType = {
13+
LITERAL: 1,
14+
VARIABLE: 2,
15+
PATH: 3,
16+
};
1217

1318
/**
1419
* Node in the router tree, either intermediate or leaf.
@@ -19,6 +24,16 @@ export class Node {
1924
*/
2025
#label;
2126

27+
/**
28+
* Type of node.
29+
*/
30+
#type;
31+
32+
/**
33+
* Parent for this node.
34+
*/
35+
#parent;
36+
2237
/**
2338
* Literal children of this node.
2439
*/
@@ -39,27 +54,29 @@ export class Node {
3954
*/
4055
#route;
4156

42-
constructor(label) {
57+
constructor(label, type = NodeType.LITERAL, parent = undefined) {
4358
this.#label = label;
59+
this.#type = type;
60+
this.#parent = parent;
4461
this.#children = [];
4562
}
4663

4764
#getOrCreateChild(seg) {
4865
if (seg === '*') {
4966
if (!this.#star) {
50-
this.#star = new Node(seg);
67+
this.#star = new Node(seg, NodeType.PATH, this);
5168
}
5269
return this.#star;
5370
}
5471
if (seg.startsWith(':')) {
5572
if (!this.#variable) {
56-
this.#variable = new Node(seg.substring(1));
73+
this.#variable = new Node(seg.substring(1), NodeType.VARIABLE, this);
5774
}
5875
return this.#variable;
5976
}
6077
let ret = this.#children.find((child) => child.#label === seg);
6178
if (!ret) {
62-
ret = new Node(seg);
79+
ret = new Node(seg, NodeType.LITERAL, this);
6380
this.#children.push(ret);
6481
}
6582
return ret;
@@ -113,4 +130,31 @@ export class Node {
113130
}
114131
return null;
115132
}
133+
134+
/**
135+
* Returns the external path by traversing from a leaf back
136+
* to the root.
137+
*
138+
* @param {string[]} segs path segments to collect
139+
* @param {Map} variables variables
140+
* @returns {void}
141+
*/
142+
external(segs, variables) {
143+
const label = this.#label;
144+
145+
switch (this.#type) {
146+
case NodeType.LITERAL:
147+
segs.unshift(label);
148+
break;
149+
case NodeType.VARIABLE:
150+
segs.unshift(variables[label]);
151+
break;
152+
case NodeType.PATH:
153+
segs.unshift(variables.path);
154+
break;
155+
default:
156+
break;
157+
}
158+
this.#parent?.external(segs, variables);
159+
}
116160
}

src/router/router.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export default class Router {
3131
#routes;
3232

3333
constructor(nameSelector) {
34-
this.#root = new Node('', (info, segs) => segs.push(''));
34+
this.#root = new Node('');
3535
this.#nameSelector = nameSelector;
3636
this.#routes = new Map();
3737
}
@@ -73,4 +73,23 @@ export default class Router {
7373
}
7474
return null;
7575
}
76+
77+
/**
78+
* Returns the external path for a route with some variables
79+
* to fill in the variable segments traversing.
80+
*
81+
* @param {string} name route name
82+
* @param {Map} variables variables
83+
* @returns {string} external path
84+
*/
85+
external(name, variables) {
86+
/** @type {Node} */
87+
const route = this.#routes.get(name);
88+
if (!route) {
89+
throw new Error(`route not found: ${name}`);
90+
}
91+
const segs = [];
92+
route.external(segs, variables);
93+
return segs.join('/');
94+
}
7695
}

src/status/status.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export default async function status(context, info) {
112112
live: await getLiveInfo(context, info),
113113
preview: await getPreviewInfo(context, info),
114114
edit,
115-
// TODO links: getAPIUrls(context, info, 'status', 'preview', 'live', 'code'),
115+
links: info.getAPIUrls('status', 'preview', 'live', 'code'),
116116
};
117117

118118
if (authInfo.profile) {

src/support/RequestInfo.js

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ class PathInfo {
207207
export class RequestInfo {
208208
#request;
209209

210+
#router;
211+
210212
#pathInfo;
211213

212214
#owner;
@@ -215,8 +217,9 @@ export class RequestInfo {
215217

216218
#ref;
217219

218-
constructor(request, pathInfo) {
220+
constructor(request, router, pathInfo) {
219221
this.#request = request;
222+
this.#router = router;
220223
this.#pathInfo = pathInfo;
221224
}
222225

@@ -310,6 +313,7 @@ export class RequestInfo {
310313
* Create a new request info.
311314
*
312315
* @param {import('@adobe/fetch').Request} request request
316+
* @param {import('../router/router.js').default} router router
313317
* @param {object} param0 params
314318
* @param {string} [param0.org] org, optional
315319
* @param {string} [param0.site] site, optional
@@ -318,13 +322,13 @@ export class RequestInfo {
318322
* @param {string} [param0.route] route, optional
319323
* @returns {RequestInfo}
320324
*/
321-
static create(request, {
325+
static create(request, router, {
322326
org, site, path, ref, route,
323327
} = {}) {
324328
const httpRequest = new HttpRequest(request);
325329
const pathInfo = new PathInfo(route, org, site, path);
326330

327-
return Object.freeze(new RequestInfo(httpRequest, pathInfo).withRef(ref));
331+
return Object.freeze(new RequestInfo(httpRequest, router, pathInfo).withRef(ref));
328332
}
329333

330334
/**
@@ -343,6 +347,7 @@ export class RequestInfo {
343347
}) {
344348
const info = new RequestInfo(
345349
other.#request,
350+
other.#router,
346351
PathInfo.clone(other.#pathInfo, {
347352
org, site, path, route,
348353
}),
@@ -375,6 +380,21 @@ export class RequestInfo {
375380
return url.href;
376381
}
377382

383+
getAPIUrls(...routes) {
384+
const links = {};
385+
const variables = {
386+
org: this.org,
387+
site: this.site,
388+
path: this.webPath.slice(1),
389+
ref: this.ref,
390+
};
391+
routes.forEach((name) => {
392+
const path = this.#router.external(name, variables);
393+
links[name] = this.getLinkUrl(path);
394+
});
395+
return links;
396+
}
397+
378398
toResourcePath() {
379399
return toResourcePath(this.webPath);
380400
}

test/index.test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ describe('Index Tests', () => {
141141
assert.strictEqual(result.status, 200);
142142
assert.deepStrictEqual(await result.json(), {
143143
edit: {},
144+
links: {
145+
code: 'https://api.aem.live/org/sites/site/code/main/document',
146+
live: 'https://api.aem.live/org/sites/site/live/document',
147+
preview: 'https://api.aem.live/org/sites/site/preview/document',
148+
status: 'https://api.aem.live/org/sites/site/status/document',
149+
},
144150
live: {
145151
contentBusId: `helix-content-bus/${SITE_CONFIG.content.contentBusId}/live/document.md`,
146152
contentType: 'text/plain; charset=utf-8',

test/live/info.test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ describe('Live Info Tests', () => {
6565

6666
assert.strictEqual(response.status, 200);
6767
assert.deepStrictEqual(await response.json(), {
68+
links: {
69+
code: 'https://api.aem.live/org/sites/site/code/main/document',
70+
live: 'https://api.aem.live/org/sites/site/live/document',
71+
preview: 'https://api.aem.live/org/sites/site/preview/document',
72+
status: 'https://api.aem.live/org/sites/site/status/document',
73+
},
6874
live: {
6975
contentBusId: `helix-content-bus/${SITE_CONFIG.content.contentBusId}/live/document.md`,
7076
contentType: 'text/plain; charset=utf-8',

test/live/publish.test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,12 @@ describe('Publish Action Tests', () => {
257257

258258
assert.strictEqual(response.status, 200);
259259
assert.deepStrictEqual(await response.json(), {
260+
links: {
261+
code: 'https://api.aem.live/org/sites/site/code/main/',
262+
live: 'https://api.aem.live/org/sites/site/live/',
263+
preview: 'https://api.aem.live/org/sites/site/preview/',
264+
status: 'https://api.aem.live/org/sites/site/status/',
265+
},
260266
live: {
261267
configRedirectLocation: '/target',
262268
contentBusId: `helix-content-bus/${SITE_CONFIG.content.contentBusId}/live/index.md`,

0 commit comments

Comments
 (0)