From 05f6896943c41a63c1a50bcdd6a3ae3bd5b2bc07 Mon Sep 17 00:00:00 2001 From: Juunini Date: Wed, 11 Oct 2023 15:06:30 +0900 Subject: [PATCH] Improved usability of the `.read` method --- README.md | 15 +++++++++++ package.json | 2 +- src/reader.test.ts | 26 ++++++++++++++++++- src/reader.ts | 63 ++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 93 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index dbce41d..96a3319 100644 --- a/README.md +++ b/README.md @@ -97,9 +97,24 @@ const imageURL = jsonld .stringOrThrow() // https://files.mastodon.social/accounts/headers/109/408/471/076/954/889/original/f4158a0d06a05763.png +const imageURL = jsonld + .read('image') + .read('url') + .stringOrThrow() +// https://files.mastodon.social/accounts/headers/109/408/471/076/954/889/original/f4158a0d06a05763.png + const id = jsonld.read('@id').get() // https://mastodon.social/users/juunini +const id = jsonld.read('id').get() +// https://mastodon.social/users/juunini + +const type = jsonld.read('@type').get() +// Person + +const type = jsonld.read('type').get() +// Person + const manuallyApprovesFollowers = jsonld .setNamespace({ as: 'https://www.w3.org/ns/activitystreams' }) .read('as', 'manuallyApprovesFollowers') diff --git a/package.json b/package.json index 91b41d2..923084f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cloudmatelabs/jsonld-helper", - "version": "1.0.0", + "version": "1.1.0", "description": "JSON-LD Helper", "homepage": "https://github.com/cloudmatelabs/jsonld-helper-ts", "repository": "cloudmatelabs/jsonld-helper-ts", diff --git a/src/reader.test.ts b/src/reader.test.ts index 0d8c5fb..8b454d2 100644 --- a/src/reader.test.ts +++ b/src/reader.test.ts @@ -20,7 +20,7 @@ describe('read', () => { describe('when given key is number, but value is not array', () => { it('should changes type Nothing', async () => { const jsonld = await JsonLDReader.parse(givenJSONLD) - expect(() => jsonld.read(0).getOrThrow()).toThrow('Not an array') + expect(() => jsonld.read(0).read(0).getOrThrow()).toThrow('Not an array') }) }) @@ -42,6 +42,23 @@ describe('read', () => { ).toBe('https://mastodon.social/users/juunini/outbox') }) }) + + describe('when not given namespace, find key', () => { + it('should return value', async () => { + const jsonld = await JsonLDReader.parse(givenJSONLD) + expect(jsonld.read('outbox').get()).toBe('https://mastodon.social/users/juunini/outbox') + }) + }) + + describe('when given key is preDefined key', () => { + it('should return value', async () => { + const jsonld = await JsonLDReader.parse(givenJSONLD) + expect(jsonld.read('@id').get()).toBe('https://mastodon.social/users/juunini') + expect(jsonld.read('id').get()).toBe('https://mastodon.social/users/juunini') + expect(jsonld.read('@type').get()).toBe('Person') + expect(jsonld.read('type').get()).toBe('Person') + }) + }) }) describe('stringOrThrow', () => { @@ -57,6 +74,13 @@ describe('stringOrThrow', () => { .read('as', 'url') .stringOrThrow() ).toBe('https://files.mastodon.social/accounts/headers/109/408/471/076/954/889/original/f4158a0d06a05763.png') + + expect( + jsonld + .read('image') + .read('url') + .stringOrThrow() + ).toBe('https://files.mastodon.social/accounts/headers/109/408/471/076/954/889/original/f4158a0d06a05763.png') }) }) diff --git a/src/reader.ts b/src/reader.ts index 90d64d1..f500a93 100644 --- a/src/reader.ts +++ b/src/reader.ts @@ -36,14 +36,14 @@ export class JsonLDReader { } /** - * parse JSON-LD value. this method uses jsonld library's expand method. but, if expanded value is single value of array, returns JsonLDReader has first object of array. + * parse JSON-LD value. this method uses jsonld library's expand method. * * @param value JSON-LD object or array of JSON-LD objects * @param options jsonld library's Options.Expand. see https://github.com/digitalbazaar/jsonld.js#custom-document-loader */ static async parse (value: object | object[], options?: Options.Expand): Promise { const data = await expand(value as JsonLdDocument, options) - return JsonLDReader.of(data.length === 1 ? data[0] : data) + return JsonLDReader.of(data) } /** @@ -56,13 +56,13 @@ export class JsonLDReader { } /** - * @param key key or index of array + * @param key key or index of array. if given key is `outbox` and has `https://www.w3.org/ns/activitystreams#outbox`, returns value of `https://www.w3.org/ns/activitystreams#outbox`. * @returns JsonLDReader instance. if key is not found, returns `Nothing` instance. */ public read (key: string | number): JsonLDReader /** * @param namespace if use `setNamespace` method to set namespace, you can use namespace as first argument. if not, insert full url as first argument. e.g. `https://www.w3.org/ns/activitystreams` - * @param key insert key. e.g. `url` + * @param key insert key. e.g. `url`. if has value is array and length is 1, it reads first element of array automatically. * @returns JsonLDReader instance. if key is not found, returns `Nothing` instance. */ public read (namespace: string, key: string): JsonLDReader @@ -224,18 +224,59 @@ export class JsonLDReader { } private readObject (key: string): JsonLDReader { - if (typeof this.value !== 'object') { + if (!this.valueIsObject()) { return new Nothing(new Error('Not an object')) } - const value = (this.value as any)?.length === 1 - ? (this.value as any[])[0] - : this.value + const scope = this.scope() as Record + const value = scope[key] - const scope = (value as Record)[key] - return scope === undefined + if (value !== undefined) { + if (key === '@type') { + return JsonLDReader.of(this.extractType(value), this.namespace) + } + return JsonLDReader.of(value, this.namespace) + } + + const extractedKey = Object.keys(scope).find((k) => k.split('#')[1] === key) + + return extractedKey === undefined ? new Nothing(new Error(`Not found key: ${key}`)) - : JsonLDReader.of(scope, this.namespace) + : JsonLDReader.of(scope[extractedKey], this.namespace) + } + + private extractType (value: string): string { + if (Array.isArray(value)) { + return this.extractType(value[0]) + } + + const hashSplit = value.split('#') + if (hashSplit.length === 2) { + return hashSplit[1] + } + + const slashSplit = value.split('/') + return slashSplit[slashSplit.length - 1] + } + + private valueIsObject (): boolean { + if (Array.isArray(this.value) && this.length === 1) { + return true + } + + if (Array.isArray(this.value)) { + return false + } + + return typeof this.value === 'object' + } + + private scope (): unknown { + if (Array.isArray(this.value) && this.length === 1) { + return this.value[0] + } + + return this.value } private getValue (): unknown {