@adobe/spacecat-shared-tokowaka-client 1.10.2 → 1.11.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [@adobe/spacecat-shared-tokowaka-client-v1.11.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-tokowaka-client-v1.10.2...@adobe/spacecat-shared-tokowaka-client-v1.11.0) (2026-03-10)
2
+
3
+ ### Features
4
+
5
+ * **tokowaka-client:** add HTML-to-HAST converter to generic mapper ([#1416](https://github.com/adobe/spacecat-shared/issues/1416)) ([510ce3b](https://github.com/adobe/spacecat-shared/commit/510ce3b267d0b68011b677e8e493a56aaaeebb87))
6
+
1
7
  ## [@adobe/spacecat-shared-tokowaka-client-v1.10.2](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-tokowaka-client-v1.10.1...@adobe/spacecat-shared-tokowaka-client-v1.10.2) (2026-03-07)
2
8
 
3
9
  ### Bug Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-tokowaka-client",
3
- "version": "1.10.2",
3
+ "version": "1.11.0",
4
4
  "description": "Tokowaka Client for SpaceCat - Edge optimization config management",
5
5
  "type": "module",
6
6
  "engines": {
@@ -12,6 +12,7 @@
12
12
 
13
13
  import { hasText } from '@adobe/spacecat-shared-utils';
14
14
  import { TARGET_USER_AGENTS_CATEGORIES } from '../constants.js';
15
+ import { htmlToHast } from '../utils/html-utils.js';
15
16
  import BaseOpportunityMapper from './base-mapper.js';
16
17
 
17
18
  /**
@@ -33,6 +34,13 @@ export default class GenericMapper extends BaseOpportunityMapper {
33
34
  return this.prerenderRequired;
34
35
  }
35
36
 
37
+ // eslint-disable-next-line class-methods-use-this
38
+ #resolveValue(data) {
39
+ if (data.format === 'html') return htmlToHast(data.patchValue);
40
+ if (data.format === 'hast' || data.format === 'json') return JSON.parse(data.patchValue);
41
+ return data.patchValue;
42
+ }
43
+
36
44
  /**
37
45
  * Converts suggestions to Tokowaka patches
38
46
  * @param {string} urlPath - URL path for the suggestions
@@ -53,12 +61,15 @@ export default class GenericMapper extends BaseOpportunityMapper {
53
61
  const data = suggestion.getData();
54
62
  const { transformRules } = data;
55
63
 
64
+ const value = this.#resolveValue(data);
65
+ const valueFormat = data.format === 'html' ? 'hast' : (data.format || 'text');
66
+
56
67
  const patch = {
57
68
  ...this.createBasePatch(suggestion, opportunityId),
58
69
  op: transformRules.action,
59
70
  selector: transformRules.selector,
60
- value: (data.format === 'hast' || data.format === 'json') ? JSON.parse(data.patchValue) : data.patchValue,
61
- valueFormat: data.format || 'text',
71
+ value,
72
+ valueFormat,
62
73
  target: TARGET_USER_AGENTS_CATEGORIES.AI_BOTS,
63
74
  };
64
75
 
@@ -12,9 +12,18 @@
12
12
 
13
13
  /* eslint-env mocha */
14
14
 
15
+ import { readFileSync } from 'fs';
16
+ import { dirname, join } from 'path';
17
+ import { fileURLToPath } from 'url';
15
18
  import { expect } from 'chai';
16
19
  import GenericMapper from '../../src/mappers/generic-mapper.js';
17
20
 
21
+ const filename = fileURLToPath(import.meta.url);
22
+ const fixturesPath = join(dirname(filename), '../fixtures/semantic-value-visibility');
23
+ const carahsoftFixture = JSON.parse(
24
+ readFileSync(join(fixturesPath, 'Carahsoft.json'), 'utf8'),
25
+ );
26
+
18
27
  describe('GenericMapper', () => {
19
28
  let mapper;
20
29
  let log;
@@ -768,6 +777,62 @@ describe('GenericMapper', () => {
768
777
  expect(patch.attrs).to.be.undefined;
769
778
  });
770
779
 
780
+ it('should convert HTML patchValue to HAST when format is html', () => {
781
+ const suggestion = {
782
+ getId: () => 'sugg-html',
783
+ getUpdatedAt: () => '2025-01-15T10:00:00.000Z',
784
+ getData: () => ({
785
+ transformRules: {
786
+ action: 'insertAfter',
787
+ selector: 'img[src="test.jpg"]',
788
+ },
789
+ patchValue: '<section data-llm-context="image"><h2>Title</h2><p>Description</p></section>',
790
+ format: 'html',
791
+ url: 'https://example.com/page',
792
+ }),
793
+ };
794
+
795
+ const patches = mapper.suggestionsToPatches('/page', [suggestion], 'opp-html');
796
+
797
+ expect(patches.length).to.equal(1);
798
+ const patch = patches[0];
799
+
800
+ expect(patch.valueFormat).to.equal('hast');
801
+ expect(patch.value).to.be.an('object');
802
+ expect(patch.value.type).to.equal('root');
803
+ const section = patch.value.children.find((c) => c.tagName === 'section');
804
+ expect(section).to.exist;
805
+ expect(section.properties.dataLlmContext).to.equal('image');
806
+ const h2 = section.children.find((c) => c.tagName === 'h2');
807
+ expect(h2).to.exist;
808
+ });
809
+
810
+ it('should convert HTML to HAST using real fixture data', () => {
811
+ const fixtureData = carahsoftFixture.suggestions[0].data;
812
+ const suggestion = {
813
+ getId: () => 'sugg-fixture',
814
+ getUpdatedAt: () => '2025-01-15T10:00:00.000Z',
815
+ getData: () => ({
816
+ transformRules: fixtureData.transformRules,
817
+ patchValue: fixtureData.semanticHtml,
818
+ format: 'html',
819
+ url: carahsoftFixture.url,
820
+ }),
821
+ };
822
+
823
+ const patches = mapper.suggestionsToPatches('/', [suggestion], 'opp-fixture');
824
+
825
+ expect(patches.length).to.equal(1);
826
+ const patch = patches[0];
827
+
828
+ expect(patch.valueFormat).to.equal('hast');
829
+ expect(patch.value.type).to.equal('root');
830
+ const section = patch.value.children.find((c) => c.tagName === 'section');
831
+ expect(section).to.exist;
832
+ expect(section.properties.dataLlmContext).to.equal('image');
833
+ expect(section.properties.dataLlmShadow).to.equal('image-text');
834
+ });
835
+
771
836
  it('should not include UI-only fields in patch', () => {
772
837
  const suggestion = {
773
838
  getId: () => 'sugg-ui',