diff --git a/src/lib/taxonomy-query.ts b/src/lib/taxonomy-query.ts index ec8ae9d6..26da6a8b 100644 --- a/src/lib/taxonomy-query.ts +++ b/src/lib/taxonomy-query.ts @@ -11,7 +11,7 @@ export class TaxonomyQuery extends Query { /** * @method find * @memberof TaxonomyQuery - * @description Fetches all taxonomies of the stack using /taxonomy-manager endpoint + * @description Fetches a list of all published taxonomies available in the stack. * @returns {Promise>} * @example * import contentstack from '@contentstack/delivery-sdk' diff --git a/src/lib/taxonomy.ts b/src/lib/taxonomy.ts index 84b05072..64a7086f 100644 --- a/src/lib/taxonomy.ts +++ b/src/lib/taxonomy.ts @@ -2,6 +2,10 @@ import { AxiosInstance, getData } from '@contentstack/core'; import { TermQuery } from './term-query'; import { Term } from './term'; +/** + * @class Taxonomy + * @description Represents a published taxonomy with methods to fetch taxonomy data and manage terms. Requires taxonomy_publish feature flag to be enabled. + */ export class Taxonomy { private _client: AxiosInstance; private _taxonomyUid: string; @@ -9,12 +13,32 @@ export class Taxonomy { _queryParams: { [key: string]: string | number } = {}; + /** + * @constructor + * @param {AxiosInstance} client - The HTTP client instance + * @param {string} taxonomyUid - The taxonomy UID + */ constructor(client: AxiosInstance, taxonomyUid: string) { this._client = client; this._taxonomyUid = taxonomyUid; this._urlPath = `/taxonomy-manager/${this._taxonomyUid}`; // TODO: change to /taxonomies/${this._taxonomyUid} } + /** + * @method term + * @memberof Taxonomy + * @description Gets a specific term or creates a term query + * @param {string} [uid] - Optional term UID. If provided, returns a Term instance. If not provided, returns a TermQuery instance. + * @returns {Term | TermQuery} + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * // Get a specific term + * const term = stack.taxonomy('taxonomy_uid').term('term_uid'); + * // Get all terms + * const termQuery = stack.taxonomy('taxonomy_uid').term(); + */ term(uid: string): Term; term(): TermQuery; term(uid?: string): Term | TermQuery { @@ -23,6 +47,17 @@ export class Taxonomy { return new TermQuery(this._client, this._taxonomyUid); } + /** + * @method fetch + * @memberof Taxonomy + * @description Fetches the taxonomy data by UID + * @returns {Promise} + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * const result = await stack.taxonomy('taxonomy_uid').fetch(); + */ async fetch(): Promise { const response = await getData(this._client, this._urlPath); diff --git a/src/lib/term-query.ts b/src/lib/term-query.ts index 23a8698f..8f0a4ce2 100644 --- a/src/lib/term-query.ts +++ b/src/lib/term-query.ts @@ -1,18 +1,38 @@ import { AxiosInstance, getData } from '@contentstack/core'; import { FindResponse } from './types'; +/** + * @class TermQuery + * @description Represents a query for fetching multiple published terms from a taxonomy. Requires taxonomy_publish feature flag to be enabled. + */ export class TermQuery { private _taxonomyUid: string; private _client: AxiosInstance; private _urlPath: string; _queryParams: { [key: string]: string | number } = {}; + /** + * @constructor + * @param {AxiosInstance} client - The HTTP client instance + * @param {string} taxonomyUid - The taxonomy UID + */ constructor(client: AxiosInstance, taxonomyUid: string) { this._client = client; this._taxonomyUid = taxonomyUid; this._urlPath = `/taxonomy-manager/${this._taxonomyUid}/terms`; } + /** + * @method find + * @memberof TermQuery + * @description Fetches a list of all published terms within a specific taxonomy. + * @returns {Promise>} + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * const result = await stack.taxonomy('taxonomy_uid').term().find(); + */ async find(): Promise> { const response = await getData(this._client, this._urlPath, { params: this._queryParams }); return response as FindResponse; diff --git a/src/lib/term.ts b/src/lib/term.ts index f33ec0e0..c4799db8 100644 --- a/src/lib/term.ts +++ b/src/lib/term.ts @@ -1,11 +1,21 @@ import { AxiosInstance, getData } from "@contentstack/core"; +/** + * @class Term + * @description Represents a published taxonomy term with methods to fetch term data, locales, ancestors, and descendants. Requires taxonomy_publish feature flag to be enabled. + */ export class Term { protected _client: AxiosInstance; private _taxonomyUid: string; private _termUid: string; private _urlPath: string; + /** + * @constructor + * @param {AxiosInstance} client - The HTTP client instance + * @param {string} taxonomyUid - The taxonomy UID + * @param {string} termUid - The term UID + */ constructor(client: AxiosInstance, taxonomyUid: string, termUid: string) { this._client = client; this._taxonomyUid = taxonomyUid; @@ -16,7 +26,7 @@ export class Term { /** * @method locales * @memberof Term - * @description Fetches locales for the term + * @description Fetches all published, localized versions of a single term. * @returns {Promise} * @example * import contentstack from '@contentstack/delivery-sdk' @@ -33,7 +43,7 @@ export class Term { /** * @method ancestors * @memberof Term - * @description Fetches ancestors for the term + * @description Fetches all ancestors of a single published term, up to the root. * @returns {Promise} * @example * import contentstack from '@contentstack/delivery-sdk' @@ -47,11 +57,37 @@ export class Term { return response; } + /** + * @method descendants + * @memberof Term + * @description Fetches all descendants of a single published term. + * @returns {Promise} + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * const result = await stack.taxonomy('taxonomy_uid').term('term_uid').descendants(); + */ + async descendants(): Promise { + const response = await getData(this._client, `${this._urlPath}/descendants`); + if (response.descendants) return response.descendants as T; + return response; + } + + /** + * @method fetch + * @memberof Term + * @description Fetches all descendants of a single published term. + * @returns {Promise} + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * const result = await stack.taxonomy('taxonomy_uid').term('term_uid').fetch(); + */ async fetch(): Promise { const response = await getData(this._client, this._urlPath); - if (response.term) return response.term as T; - return response; } } diff --git a/src/lib/types.ts b/src/lib/types.ts index a5106675..b80e80e8 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -14,25 +14,25 @@ export type queryParams = { /** * Interface for creating Contentstack plugins - * + * * @example * ```typescript * import { ContentstackPlugin } from '@contentstack/delivery-sdk'; - * + * * class MyPlugin implements ContentstackPlugin { * onRequest(config: any): any { * // Modify request configuration * console.log('Processing request:', config.url); * return { ...config, headers: { ...config.headers, 'X-Custom-Header': 'value' } }; * } - * + * * onResponse(request: any, response: any, data: any): any { * // Process response data * console.log('Processing response:', response.status); * return { ...response, data: { ...data, processed: true } }; * } * } - * + * * const stack = contentstack.stack({ * apiKey: 'your-api-key', * deliveryToken: 'your-delivery-token', @@ -342,3 +342,31 @@ export type LivePreview = { management_token?: string; preview_token?: string; }; + +export interface BaseTaxonomy { + uid: string; + name: string; + description?: string; + terms_count?: number; + created_at: string; + updated_at: string; + created_by: string; + updated_by: string; + type: string; + ACL: ACL; + publish_details?: PublishDetails; +} + +export interface BaseTerm { + taxonomy_uid: string; + uid: string; + name: string; + created_by: string; + created_at: string; + updated_by: string; + updated_at: string; + children_count?: number; + depth?: number; + ACL: ACL; + publish_details?: PublishDetails; +} \ No newline at end of file diff --git a/test/api/taxonomy.spec.ts b/test/api/taxonomy.spec.ts index 10e975c7..09a8f291 100644 --- a/test/api/taxonomy.spec.ts +++ b/test/api/taxonomy.spec.ts @@ -16,7 +16,7 @@ describe('ContentType API test cases', () => { }); it('should give a single taxonomy when taxonomy method is called with taxonomyUid', async () => { - const result = await makeTaxonomy('taxonomy_testing_3').fetch(); + const result = await makeTaxonomy('taxonomy_testing').fetch(); expect(result).toBeDefined(); }); }); diff --git a/test/api/term-query.spec.ts b/test/api/term-query.spec.ts index 8ea808db..58f59574 100644 --- a/test/api/term-query.spec.ts +++ b/test/api/term-query.spec.ts @@ -6,7 +6,7 @@ const stack = stackInstance(); describe("Terms API test cases", () => { it("should check for terms is defined", async () => { - const result = await makeTerms("taxonomy_testing_3").find(); + const result = await makeTerms("taxonomy_testing").find(); if (result.terms) { expect(result.terms).toBeDefined(); expect(result.terms[0].taxonomy_uid).toBeDefined(); diff --git a/test/api/term.spec.ts b/test/api/term.spec.ts index b09094be..3d994036 100644 --- a/test/api/term.spec.ts +++ b/test/api/term.spec.ts @@ -27,9 +27,16 @@ describe("Terms API test cases", () => { expect(result.terms).toBeDefined(); expect(result.terms[0].name).toBeDefined(); }); + + it("should get descendants for a term", async () => { + const result = await makeTerms("vrl").descendants(); + expect(result).toBeDefined(); + expect(result.terms).toBeDefined(); + expect(result.terms[0].name).toBeDefined(); + }); }); function makeTerms(termUid = ""): Term { - const terms = stack.taxonomy("taxonomy_testing_3").term(termUid); + const terms = stack.taxonomy("taxonomy_testing").term(termUid); return terms; } diff --git a/test/unit/term.spec.ts b/test/unit/term.spec.ts index 244b3e88..0c404a43 100644 --- a/test/unit/term.spec.ts +++ b/test/unit/term.spec.ts @@ -1,6 +1,6 @@ import { AxiosInstance, httpClient } from '@contentstack/core'; import MockAdapter from 'axios-mock-adapter'; -import { termQueryFindResponseDataMock, termLocalesResponseDataMock, termAncestorsResponseDataMock } from '../utils/mocks'; +import { termQueryFindResponseDataMock, termLocalesResponseDataMock, termAncestorsResponseDataMock, termDescendantsResponseDataMock } from '../utils/mocks'; import { MOCK_CLIENT_OPTIONS } from '../utils/constant'; import { Term } from '../../src/lib/term'; import { Taxonomy } from '../../src/lib/taxonomy'; @@ -39,4 +39,11 @@ describe('Term class', () => { const response = await term.ancestors(); expect(response).toEqual(termAncestorsResponseDataMock); }); + + it('should fetch descendants for a term when descendants() is called', async () => { + mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms/term1/descendants').reply(200, termDescendantsResponseDataMock); + + const response = await term.descendants(); + expect(response).toEqual(termDescendantsResponseDataMock); + }); }); diff --git a/test/utils/mocks.ts b/test/utils/mocks.ts index 5ff3626b..14957541 100644 --- a/test/utils/mocks.ts +++ b/test/utils/mocks.ts @@ -1738,6 +1738,93 @@ const termAncestorsResponseDataMock = { ] } +const termDescendantsResponseDataMock = { + "terms": [ + { + "taxonomy_uid": "taxonomy_testing", + "uid": "sleeper", + "ancestors": [ + { + "uid": "taxonomy_testing", + "name": "taxonomy_testing", + "type": "TAXONOMY" + }, + { + "uid": "vehicles", + "name": "vehicles", + "type": "" + }, + { + "uid": "buses", + "name": "buses", + "type": "" + }, + { + "uid": "vrl", + "name": "vrl", + "type": "" + } + ], + "name": "sleeper", + "parent_uid": "vrl", + "created_by": "created_by", + "created_at": "2025-10-28T07:58:46.870Z", + "updated_by": "updated_by", + "updated_at": "2025-10-28T07:58:46.870Z", + "children_count": 0, + "depth": 4, + "ACL": {}, + "publish_details": { + "time": "2025-10-28T07:59:12.557Z", + "user": "user", + "environment": "environment", + "locale": "en-us" + } + }, + { + "taxonomy_uid": "taxonomy_testing", + "uid": "intercity", + "ancestors": [ + { + "uid": "taxonomy_testing", + "name": "taxonomy_testing", + "type": "TAXONOMY" + }, + { + "uid": "vehicles", + "name": "vehicles", + "type": "" + }, + { + "uid": "buses", + "name": "buses", + "type": "" + }, + { + "uid": "vrl", + "name": "vrl", + "type": "" + } + ], + "name": "intercity", + "parent_uid": "vrl", + "created_by": "created_by", + "created_at": "2025-10-28T07:58:46.870Z", + "updated_by": "updated_by", + "updated_at": "2025-10-28T07:58:46.870Z", + "children_count": 0, + "depth": 4, + "ACL": {}, + "publish_details": { + "time": "2025-10-28T07:59:12.565Z", + "user": "user", + "environment": "environment", + "locale": "en-us" + } + } + ] +} + const termQueryFindResponseDataMock = { "terms": [ { @@ -1785,4 +1872,5 @@ export { termQueryFindResponseDataMock, termLocalesResponseDataMock, termAncestorsResponseDataMock, + termDescendantsResponseDataMock, };