@code.store/arcxp-sdk-ts 5.2.0 → 5.3.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/dist/index.cjs CHANGED
@@ -9,11 +9,11 @@ var fs = require('node:fs');
9
9
  var path = require('node:path');
10
10
  var FormData = require('form-data');
11
11
  var ws = require('ws');
12
+ var nodeHtmlParser = require('node-html-parser');
13
+ var htmlEntities = require('html-entities');
12
14
  var encode = require('base32-encode');
13
15
  var uuid = require('uuid');
14
16
  var assert = require('node:assert');
15
- var nodeHtmlParser = require('node-html-parser');
16
- var htmlEntities = require('html-entities');
17
17
 
18
18
  function _interopNamespaceDefault(e) {
19
19
  var n = Object.create(null);
@@ -137,28 +137,6 @@ class ArcAuthor extends ArcAbstractAPI {
137
137
  }
138
138
  }
139
139
 
140
- class ArcContentOps extends ArcAbstractAPI {
141
- constructor(options) {
142
- super({ ...options, apiPath: 'contentops/v1' });
143
- }
144
- async schedulePublish(payload) {
145
- const { data } = await this.client.put('/publish', payload);
146
- return data;
147
- }
148
- async scheduleUnpublish(payload) {
149
- const { data } = await this.client.put('/unpublish', payload);
150
- return data;
151
- }
152
- async unscheduleUnpublish(payload) {
153
- const { data } = await this.client.put('/unschedule_unpublish', payload);
154
- return data;
155
- }
156
- async unschedulePublish(payload) {
157
- const { data } = await this.client.put('/unschedule_publish', payload);
158
- return data;
159
- }
160
- }
161
-
162
140
  class ArcContent extends ArcAbstractAPI {
163
141
  constructor(options) {
164
142
  super({ ...options, apiPath: 'content/v4' });
@@ -183,6 +161,28 @@ class ArcContent extends ArcAbstractAPI {
183
161
  }
184
162
  }
185
163
 
164
+ class ArcContentOps extends ArcAbstractAPI {
165
+ constructor(options) {
166
+ super({ ...options, apiPath: 'contentops/v1' });
167
+ }
168
+ async schedulePublish(payload) {
169
+ const { data } = await this.client.put('/publish', payload);
170
+ return data;
171
+ }
172
+ async scheduleUnpublish(payload) {
173
+ const { data } = await this.client.put('/unpublish', payload);
174
+ return data;
175
+ }
176
+ async unscheduleUnpublish(payload) {
177
+ const { data } = await this.client.put('/unschedule_unpublish', payload);
178
+ return data;
179
+ }
180
+ async unschedulePublish(payload) {
181
+ const { data } = await this.client.put('/unschedule_publish', payload);
182
+ return data;
183
+ }
184
+ }
185
+
186
186
  class Custom extends ArcAbstractAPI {
187
187
  constructor(options) {
188
188
  super({ ...options, apiPath: '' });
@@ -196,6 +196,128 @@ class Custom extends ArcAbstractAPI {
196
196
  }
197
197
  }
198
198
 
199
+ class ArcDeveloperRetail extends ArcAbstractAPI {
200
+ constructor(options) {
201
+ super({ ...options, apiPath: 'retail/api/v1' });
202
+ }
203
+ // ============================================
204
+ // Product Methods
205
+ // ============================================
206
+ async getProductById(id, params) {
207
+ const { data } = await this.client.get(`/product/${id}`, { params });
208
+ return data;
209
+ }
210
+ async getProductBySku(sku, params) {
211
+ const { data } = await this.client.get(`/product/sku/${sku}`, { params });
212
+ return data;
213
+ }
214
+ async getProductByPriceCode(priceCode, params) {
215
+ const { data } = await this.client.get(`/product/pricecode/${priceCode}`, { params });
216
+ return data;
217
+ }
218
+ async getAllProducts(params) {
219
+ const { data } = await this.client.get('/product', { params });
220
+ return data;
221
+ }
222
+ // ============================================
223
+ // Pricing Strategy Methods
224
+ // ============================================
225
+ async getPricingStrategyById(id, params) {
226
+ const { data } = await this.client.get(`/pricing/strategy/${id}`, { params });
227
+ return data;
228
+ }
229
+ async getAllPricingStrategies(params) {
230
+ const { data } = await this.client.get('/pricing/strategy', { params });
231
+ return data;
232
+ }
233
+ // ============================================
234
+ // Pricing Rate Methods
235
+ // ============================================
236
+ async getPricingRateById(id, params) {
237
+ const { data } = await this.client.get(`/pricing/rate/${id}`, { params });
238
+ return data;
239
+ }
240
+ async getAllPricingRates(params) {
241
+ const { data } = await this.client.get('/pricing/rate', { params });
242
+ return data;
243
+ }
244
+ // ============================================
245
+ // Pricing Cycle Methods
246
+ // ============================================
247
+ async getPricingCycle(priceCode, cycleIndex, startDate, params) {
248
+ const { data } = await this.client.get(`/pricing/cycle/${priceCode}/${cycleIndex}/${startDate}`, {
249
+ params,
250
+ });
251
+ return data;
252
+ }
253
+ // ============================================
254
+ // Campaign Methods
255
+ // ============================================
256
+ async getCampaignById(id, params) {
257
+ const { data } = await this.client.get(`/campaign/${id}`, { params });
258
+ return data;
259
+ }
260
+ async getCampaignByName(campaignName, params) {
261
+ const { data } = await this.client.get(`/campaign/${campaignName}/get`, { params });
262
+ return data;
263
+ }
264
+ async getAllCampaigns(params) {
265
+ const { data } = await this.client.get('/campaign', { params });
266
+ return data;
267
+ }
268
+ // ============================================
269
+ // Campaign Category Methods
270
+ // ============================================
271
+ async getCampaignCategoryById(id, params) {
272
+ const { data } = await this.client.get(`/campaign/category/${id}`, { params });
273
+ return data;
274
+ }
275
+ async getAllCampaignCategories(params) {
276
+ const { data } = await this.client.get('/campaign/category', { params });
277
+ return data;
278
+ }
279
+ // ============================================
280
+ // Offer Methods
281
+ // ============================================
282
+ async getOfferById(id, params) {
283
+ const { data } = await this.client.get(`/offer/${id}`, { params });
284
+ return data;
285
+ }
286
+ async getAllOffers(params) {
287
+ const { data } = await this.client.get('/offer', { params });
288
+ return data;
289
+ }
290
+ // ============================================
291
+ // Offer Attribute Methods
292
+ // ============================================
293
+ async getOfferAttributeById(id, params) {
294
+ const { data } = await this.client.get(`/offer/attribute/${id}`, { params });
295
+ return data;
296
+ }
297
+ async getAllOfferAttributes(params) {
298
+ const { data } = await this.client.get('/offer/attribute', { params });
299
+ return data;
300
+ }
301
+ // ============================================
302
+ // Product Attribute Methods
303
+ // ============================================
304
+ async getProductAttributeById(id, params) {
305
+ const { data } = await this.client.get(`/product/attribute/${id}`, { params });
306
+ return data;
307
+ }
308
+ async getAllProductAttributes(params) {
309
+ const { data } = await this.client.get('/product/attribute', { params });
310
+ return data;
311
+ }
312
+ // ============================================
313
+ // Condition Category Methods
314
+ // ============================================
315
+ async getAllConditionCategories(params) {
316
+ const { data } = await this.client.get('/condition/categories', { params });
317
+ return data;
318
+ }
319
+ }
320
+
199
321
  class ArcDraft extends ArcAbstractAPI {
200
322
  constructor(options) {
201
323
  super({ ...options, apiPath: 'draft/v1' });
@@ -592,190 +714,68 @@ class ArcRetailEvents {
592
714
  }
593
715
  }
594
716
 
595
- class ArcDeveloperRetail extends ArcAbstractAPI {
717
+ class ArcSales extends ArcAbstractAPI {
596
718
  constructor(options) {
597
- super({ ...options, apiPath: 'retail/api/v1' });
719
+ super({ ...options, apiPath: 'sales/api/v1' });
598
720
  }
599
- // ============================================
600
- // Product Methods
601
- // ============================================
602
- async getProductById(id, params) {
603
- const { data } = await this.client.get(`/product/${id}`, { params });
721
+ async migrate(params, payload) {
722
+ const FormData = await platform.form_data();
723
+ const form = new FormData();
724
+ form.append('file', JSON.stringify(payload), { filename: 'subs.json', contentType: 'application/json' });
725
+ const { data } = await this.client.post('/migrate', form, {
726
+ params,
727
+ headers: {
728
+ ...form.getHeaders(),
729
+ },
730
+ });
604
731
  return data;
605
732
  }
606
- async getProductBySku(sku, params) {
607
- const { data } = await this.client.get(`/product/sku/${sku}`, { params });
608
- return data;
733
+ }
734
+ class ArcSalesV2 extends ArcAbstractAPI {
735
+ constructor(options) {
736
+ super({ ...options, apiPath: 'sales/api/v2' });
609
737
  }
610
- async getProductByPriceCode(priceCode, params) {
611
- const { data } = await this.client.get(`/product/pricecode/${priceCode}`, { params });
738
+ async getEnterpriseGroups(params) {
739
+ const { data } = await this.client.get('/subscriptions/enterprise', {
740
+ params: {
741
+ 'arc-site': params.site,
742
+ },
743
+ });
612
744
  return data;
613
745
  }
614
- async getAllProducts(params) {
615
- const { data } = await this.client.get('/product', { params });
746
+ async createEnterpriseGroup(params, payload) {
747
+ const { data } = await this.client.post('/subscriptions/enterprise', payload, {
748
+ params: {
749
+ 'arc-site': params.site,
750
+ },
751
+ });
616
752
  return data;
617
753
  }
618
- // ============================================
619
- // Pricing Strategy Methods
620
- // ============================================
621
- async getPricingStrategyById(id, params) {
622
- const { data } = await this.client.get(`/pricing/strategy/${id}`, { params });
754
+ async createNonce(website, enterpriseGroupId) {
755
+ const { data } = await this.client.get(`/subscriptions/enterprise/${enterpriseGroupId}`, {
756
+ params: { 'arc-site': website },
757
+ });
623
758
  return data;
624
759
  }
625
- async getAllPricingStrategies(params) {
626
- const { data } = await this.client.get('/pricing/strategy', { params });
627
- return data;
760
+ }
761
+
762
+ class ArcSigningService extends ArcAbstractAPI {
763
+ constructor(options) {
764
+ super({ ...options, apiPath: 'signing-service' });
628
765
  }
629
- // ============================================
630
- // Pricing Rate Methods
631
- // ============================================
632
- async getPricingRateById(id, params) {
633
- const { data } = await this.client.get(`/pricing/rate/${id}`, { params });
766
+ async sign(service, serviceVersion, imageId) {
767
+ const { data } = await this.client.get(`/v2/sign/${service}/${serviceVersion}?value=${encodeURI(imageId)}`);
634
768
  return data;
635
769
  }
636
- async getAllPricingRates(params) {
637
- const { data } = await this.client.get('/pricing/rate', { params });
638
- return data;
770
+ }
771
+
772
+ class ArcSite extends ArcAbstractAPI {
773
+ constructor(options) {
774
+ super({ ...options, apiPath: 'site/v3' });
639
775
  }
640
- // ============================================
641
- // Pricing Cycle Methods
642
- // ============================================
643
- async getPricingCycle(priceCode, cycleIndex, startDate, params) {
644
- const { data } = await this.client.get(`/pricing/cycle/${priceCode}/${cycleIndex}/${startDate}`, {
645
- params,
646
- });
647
- return data;
648
- }
649
- // ============================================
650
- // Campaign Methods
651
- // ============================================
652
- async getCampaignById(id, params) {
653
- const { data } = await this.client.get(`/campaign/${id}`, { params });
654
- return data;
655
- }
656
- async getCampaignByName(campaignName, params) {
657
- const { data } = await this.client.get(`/campaign/${campaignName}/get`, { params });
658
- return data;
659
- }
660
- async getAllCampaigns(params) {
661
- const { data } = await this.client.get('/campaign', { params });
662
- return data;
663
- }
664
- // ============================================
665
- // Campaign Category Methods
666
- // ============================================
667
- async getCampaignCategoryById(id, params) {
668
- const { data } = await this.client.get(`/campaign/category/${id}`, { params });
669
- return data;
670
- }
671
- async getAllCampaignCategories(params) {
672
- const { data } = await this.client.get('/campaign/category', { params });
673
- return data;
674
- }
675
- // ============================================
676
- // Offer Methods
677
- // ============================================
678
- async getOfferById(id, params) {
679
- const { data } = await this.client.get(`/offer/${id}`, { params });
680
- return data;
681
- }
682
- async getAllOffers(params) {
683
- const { data } = await this.client.get('/offer', { params });
684
- return data;
685
- }
686
- // ============================================
687
- // Offer Attribute Methods
688
- // ============================================
689
- async getOfferAttributeById(id, params) {
690
- const { data } = await this.client.get(`/offer/attribute/${id}`, { params });
691
- return data;
692
- }
693
- async getAllOfferAttributes(params) {
694
- const { data } = await this.client.get('/offer/attribute', { params });
695
- return data;
696
- }
697
- // ============================================
698
- // Product Attribute Methods
699
- // ============================================
700
- async getProductAttributeById(id, params) {
701
- const { data } = await this.client.get(`/product/attribute/${id}`, { params });
702
- return data;
703
- }
704
- async getAllProductAttributes(params) {
705
- const { data } = await this.client.get('/product/attribute', { params });
706
- return data;
707
- }
708
- // ============================================
709
- // Condition Category Methods
710
- // ============================================
711
- async getAllConditionCategories(params) {
712
- const { data } = await this.client.get('/condition/categories', { params });
713
- return data;
714
- }
715
- }
716
-
717
- class ArcSales extends ArcAbstractAPI {
718
- constructor(options) {
719
- super({ ...options, apiPath: 'sales/api/v1' });
720
- }
721
- async migrate(params, payload) {
722
- const FormData = await platform.form_data();
723
- const form = new FormData();
724
- form.append('file', JSON.stringify(payload), { filename: 'subs.json', contentType: 'application/json' });
725
- const { data } = await this.client.post('/migrate', form, {
726
- params,
727
- headers: {
728
- ...form.getHeaders(),
729
- },
730
- });
731
- return data;
732
- }
733
- }
734
- class ArcSalesV2 extends ArcAbstractAPI {
735
- constructor(options) {
736
- super({ ...options, apiPath: 'sales/api/v2' });
737
- }
738
- async getEnterpriseGroups(params) {
739
- const { data } = await this.client.get('/subscriptions/enterprise', {
740
- params: {
741
- 'arc-site': params.site,
742
- },
743
- });
744
- return data;
745
- }
746
- async createEnterpriseGroup(params, payload) {
747
- const { data } = await this.client.post('/subscriptions/enterprise', payload, {
748
- params: {
749
- 'arc-site': params.site,
750
- },
751
- });
752
- return data;
753
- }
754
- async createNonce(website, enterpriseGroupId) {
755
- const { data } = await this.client.get(`/subscriptions/enterprise/${enterpriseGroupId}`, {
756
- params: { 'arc-site': website },
757
- });
758
- return data;
759
- }
760
- }
761
-
762
- class ArcSigningService extends ArcAbstractAPI {
763
- constructor(options) {
764
- super({ ...options, apiPath: 'signing-service' });
765
- }
766
- async sign(service, serviceVersion, imageId) {
767
- const { data } = await this.client.get(`/v2/sign/${service}/${serviceVersion}?value=${encodeURI(imageId)}`);
768
- return data;
769
- }
770
- }
771
-
772
- class ArcSite extends ArcAbstractAPI {
773
- constructor(options) {
774
- super({ ...options, apiPath: 'site/v3' });
775
- }
776
- async getSections(params) {
777
- const { data } = await this.client.get(`/website/${params.website}/section`, {
778
- params: { _website: params.website, ...params },
776
+ async getSections(params) {
777
+ const { data } = await this.client.get(`/website/${params.website}/section`, {
778
+ params: { _website: params.website, ...params },
779
779
  });
780
780
  return data;
781
781
  }
@@ -913,84 +913,6 @@ const ArcAPI = (options) => {
913
913
  return API;
914
914
  };
915
915
 
916
- /* eslint-disable */
917
- /**
918
- * This file was automatically generated by json-schema-to-typescript.
919
- * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
920
- * and run json-schema-to-typescript to regenerate this file.
921
- */
922
-
923
- var ansTypes = /*#__PURE__*/Object.freeze({
924
- __proto__: null
925
- });
926
-
927
- var utils = /*#__PURE__*/Object.freeze({
928
- __proto__: null
929
- });
930
-
931
- var ANSType;
932
- (function (ANSType) {
933
- ANSType["Story"] = "story";
934
- ANSType["Video"] = "video";
935
- ANSType["Tag"] = "tag";
936
- ANSType["Author"] = "author";
937
- ANSType["Gallery"] = "gallery";
938
- ANSType["Image"] = "image";
939
- ANSType["Redirect"] = "redirect";
940
- })(ANSType || (ANSType = {}));
941
- var MigrationStatus;
942
- (function (MigrationStatus) {
943
- MigrationStatus["Success"] = "Success";
944
- MigrationStatus["Queued"] = "Queued";
945
- MigrationStatus["Circulated"] = "Circulated";
946
- MigrationStatus["Published"] = "Published";
947
- MigrationStatus["Scheduled"] = "Scheduled";
948
- MigrationStatus["FailVideo"] = "FailVideo";
949
- MigrationStatus["FailImage"] = "FailImage";
950
- MigrationStatus["FailPhoto"] = "FailPhoto";
951
- MigrationStatus["FailStory"] = "FailStory";
952
- MigrationStatus["FailGallery"] = "FailGallery";
953
- MigrationStatus["FailAuthor"] = "FailAuthor";
954
- MigrationStatus["FailTag"] = "FailTag";
955
- MigrationStatus["ValidationFailed"] = "ValidationFailed";
956
- })(MigrationStatus || (MigrationStatus = {}));
957
- var SummarySortBy;
958
- (function (SummarySortBy) {
959
- SummarySortBy["CreateDate"] = "createDate";
960
- SummarySortBy["UpdateDate"] = "updateDate";
961
- SummarySortBy["Id"] = "id";
962
- })(SummarySortBy || (SummarySortBy = {}));
963
- var SummarySortOrder;
964
- (function (SummarySortOrder) {
965
- SummarySortOrder["ASC"] = "ASC";
966
- SummarySortOrder["DESC"] = "DESC";
967
- })(SummarySortOrder || (SummarySortOrder = {}));
968
-
969
- var index$3 = /*#__PURE__*/Object.freeze({
970
- __proto__: null,
971
- ANS: ansTypes,
972
- get ANSType () { return ANSType; },
973
- get MigrationStatus () { return MigrationStatus; },
974
- get SummarySortBy () { return SummarySortBy; },
975
- get SummarySortOrder () { return SummarySortOrder; },
976
- TypeUtils: utils
977
- });
978
-
979
- const reference = (ref) => {
980
- return {
981
- _id: ref.id,
982
- type: 'reference',
983
- referent: {
984
- ...ref,
985
- },
986
- };
987
- };
988
-
989
- var ANS = /*#__PURE__*/Object.freeze({
990
- __proto__: null,
991
- reference: reference
992
- });
993
-
994
916
  const ContentElement = {
995
917
  divider: () => {
996
918
  return {
@@ -1223,18 +1145,60 @@ const ContentElement = {
1223
1145
  },
1224
1146
  };
1225
1147
 
1148
+ const BLOCK_ELEMENT_TAGS = [
1149
+ 'ADDRESS',
1150
+ 'ARTICLE',
1151
+ 'ASIDE',
1152
+ 'BLOCKQUOTE',
1153
+ 'DETAILS',
1154
+ 'DIV',
1155
+ 'DL',
1156
+ 'FIELDSET',
1157
+ 'FIGCAPTION',
1158
+ 'FIGURE',
1159
+ 'FOOTER',
1160
+ 'FORM',
1161
+ 'H1',
1162
+ 'H2',
1163
+ 'H3',
1164
+ 'H4',
1165
+ 'H5',
1166
+ 'H6',
1167
+ 'HEADER',
1168
+ 'HR',
1169
+ 'LINE',
1170
+ 'MAIN',
1171
+ 'MENU',
1172
+ 'NAV',
1173
+ 'OL',
1174
+ 'P',
1175
+ 'PARAGRAPH',
1176
+ 'PRE',
1177
+ 'SECTION',
1178
+ 'TABLE',
1179
+ 'UL',
1180
+ 'LI',
1181
+ 'BODY',
1182
+ 'HTML',
1183
+ ];
1184
+
1185
+ var html_constants = /*#__PURE__*/Object.freeze({
1186
+ __proto__: null,
1187
+ BLOCK_ELEMENT_TAGS: BLOCK_ELEMENT_TAGS
1188
+ });
1189
+
1226
1190
  const socialRegExps = {
1227
- instagram: /(?:https?:\/\/)?(?:www.)?instagram.com\/?([a-zA-Z0-9\.\_\-]+)?\/([p]+)?([reel]+)?([tv]+)?([stories]+)?\/([a-zA-Z0-9\-\_\.]+)\/?([0-9]+)?/,
1228
- twitter: /https:\/\/(?:www\.)?twitter\.com\/[^\/]+\/status(?:es)?\/(\d+)/,
1229
- tiktok: /https:\/\/(?:m|www|vm)?\.?tiktok\.com\/((?:.*\b(?:(?:usr|v|embed|user|video)\/|\?shareId=|\&item_id=)(\d+))|\w+)/,
1230
- facebookPost: /https:\/\/www\.facebook\.com\/(photo(\.php|s)|permalink\.php|media|questions|notes|[^\/]+\/(activity|posts))[\/?].*$/,
1231
- facebookVideo: /https:\/\/www\.facebook\.com\/([^\/?].+\/)?video(s|\.php)[\/?].*/,
1191
+ instagram: /(?:https?:\/\/)?(?:www.)?instagram.com\/?([a-zA-Z0-9._-]+)?\/([p]+)?([reel]+)?([tv]+)?([stories]+)?\/([a-zA-Z0-9\-_.]+)\/?([0-9]+)?/,
1192
+ twitter: /https:\/\/(?:www\.)?twitter\.com\/[^/]+\/status(?:es)?\/(\d+)/,
1193
+ tiktok: /https:\/\/(?:m|www|vm)?\.?tiktok\.com\/((?:.*\b(?:(?:usr|v|embed|user|video)\/|\?shareId=|&item_id=)(\d+))|\w+)/,
1194
+ facebookPost: /https:\/\/www\.facebook\.com\/(photo(\.php|s)|permalink\.php|media|questions|notes|[^/]+\/(activity|posts))[/?].*$/,
1195
+ facebookVideo: /https:\/\/www\.facebook\.com\/([^/?].+\/)?video(s|\.php)[/?].*/,
1232
1196
  };
1233
1197
  function match(url, regex) {
1234
1198
  return url.match(regex)?.[0];
1235
1199
  }
1236
1200
  function youtubeURLParser(url = '') {
1237
- const regExp = /(?:youtube(?:-nocookie)?\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]vi?=)|youtu\.be\/)([a-zA-Z0-9_-]{11})/;
1201
+ const regExp = /(?:youtube(?:-nocookie)?\.com\/(?:[^/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]vi?=)|youtu\.be\/)([a-zA-Z0-9_-]{11})/;
1238
1202
  const id = url?.match(regExp)?.[1];
1239
1203
  if (id) {
1240
1204
  return `https://youtu.be/${id}`;
@@ -1289,257 +1253,459 @@ function createSocial(url = '') {
1289
1253
  return embeds;
1290
1254
  }
1291
1255
  const randomId = () => `${new Date().toISOString()}-${Math.random()}`;
1256
+ const isTextCE = (ce) => {
1257
+ return ce?.type === 'text';
1258
+ };
1259
+ const decodeHTMLEntities = (str) => htmlEntities.decode(str);
1292
1260
 
1293
1261
  var ContentElements = /*#__PURE__*/Object.freeze({
1294
1262
  __proto__: null,
1295
1263
  createSocial: createSocial,
1264
+ decodeHTMLEntities: decodeHTMLEntities,
1296
1265
  facebookPostURLParser: facebookPostURLParser,
1297
1266
  facebookVideoURLParser: facebookVideoURLParser,
1298
1267
  instagramURLParser: instagramURLParser,
1268
+ isTextCE: isTextCE,
1299
1269
  randomId: randomId,
1300
1270
  tiktokURLParser: tiktokURLParser,
1301
1271
  twitterURLParser: twitterURLParser,
1302
1272
  youtubeURLParser: youtubeURLParser
1303
1273
  });
1304
1274
 
1305
- const generateArcId = (identifier, orgHostname) => {
1306
- const namespace = uuid.v5(orgHostname, uuid.v5.DNS);
1307
- const buffer = uuid.v5(identifier, namespace, Buffer.alloc(16));
1308
- return encode(buffer, 'RFC4648', { padding: false });
1275
+ const isTextNode = (node) => {
1276
+ return node instanceof nodeHtmlParser.TextNode;
1309
1277
  };
1310
- /**
1311
- * Utility class for generating Arc IDs and source IDs
1312
- *
1313
- * @example
1314
- * ```ts
1315
- * const generator = new IdGenerator(['my-org']);
1316
- * const arcId = generator.getArcId('123'); // Generates a unique for 'my-org' Arc ID
1317
- * const sourceId = generator.getSourceId('123', ['my-site']); // Generates 'my-site-123'
1318
- * ```
1319
- */
1320
- class IdGenerator {
1321
- constructor(namespaces) {
1322
- if (!namespaces.length) {
1323
- throw new Error('At least 1 namespace is required');
1324
- }
1325
- this.namespace = namespaces.join('-');
1326
- }
1327
- getArcId(id) {
1328
- return generateArcId(id.toString(), this.namespace);
1329
- }
1330
- getSourceId(id, prefixes = []) {
1331
- return [...prefixes, id].join('-');
1332
- }
1333
- }
1334
-
1335
- var Id = /*#__PURE__*/Object.freeze({
1336
- __proto__: null,
1337
- IdGenerator: IdGenerator,
1338
- generateArcId: generateArcId
1339
- });
1340
-
1341
- const buildTree = (items) => {
1342
- const tree = [
1343
- {
1344
- id: '/',
1345
- children: [],
1346
- meta: new Proxy({}, {
1347
- get: () => {
1348
- throw new Error('Root node meta is not accessible');
1349
- },
1350
- }),
1351
- parent: null,
1352
- },
1353
- ];
1354
- // Track nodes at each level to maintain parent-child relationships
1355
- // stores last node at each level
1356
- const currLevelNodes = {
1357
- 0: tree[0],
1358
- };
1359
- for (const item of items) {
1360
- const node = {
1361
- id: item.id,
1362
- parent: null,
1363
- children: [],
1364
- meta: item,
1365
- };
1366
- // Determine the level of this node
1367
- const levelKey = Object.keys(item).find((key) => key.startsWith('N') && item[key]);
1368
- const level = Number(levelKey?.replace('N', '')) || 0;
1369
- if (!level) {
1370
- throw new Error(`Invalid level for section ${item.id}`);
1371
- }
1372
- // This is a child node - attach to its parent
1373
- const parentLevel = level - 1;
1374
- const parentNode = currLevelNodes[parentLevel];
1375
- if (parentNode) {
1376
- node.parent = parentNode;
1377
- parentNode.children.push(node);
1378
- }
1379
- else {
1380
- throw new Error(`Parent node not found for section ${item.id}`);
1381
- }
1382
- // Set this as the current node for its level
1383
- currLevelNodes[level] = node;
1384
- }
1385
- // return root nodes children
1386
- return tree[0].children;
1278
+ const isHTMLElement = (node) => {
1279
+ return node instanceof nodeHtmlParser.HTMLElement;
1387
1280
  };
1388
- const flattenTree = (tree) => {
1389
- const flatten = [];
1390
- const traverse = (node) => {
1391
- flatten.push(node);
1392
- for (const child of node.children) {
1393
- traverse(child);
1394
- }
1395
- };
1396
- // traverse all root nodes and their children
1397
- for (const node of tree) {
1398
- traverse(node);
1399
- }
1400
- return flatten;
1281
+ const isCommentNode = (node) => {
1282
+ return node instanceof nodeHtmlParser.CommentNode;
1401
1283
  };
1402
- const buildAndFlattenTree = (items) => flattenTree(buildTree(items));
1403
- const groupByWebsites = (sections) => {
1404
- return sections.reduce((acc, section) => {
1405
- const website = section._website;
1406
- if (!acc[website])
1407
- acc[website] = [];
1408
- acc[website].push(section);
1409
- return acc;
1410
- }, {});
1284
+ const nodeTagIs = (node, name) => {
1285
+ return isHTMLElement(node) && node.tagName?.toLowerCase() === name.toLowerCase();
1411
1286
  };
1412
- const references = (sections) => {
1413
- return sections.map((s) => reference({
1414
- id: s._id,
1415
- website: s._website,
1416
- type: 'section',
1417
- }));
1287
+ const nodeTagIn = (node, names) => {
1288
+ return isHTMLElement(node) && names.includes(node.tagName?.toLowerCase());
1418
1289
  };
1419
- const isReference = (section) => {
1420
- return section?.type === 'reference' && section?.referent?.type === 'section';
1290
+ const htmlToText = (html, parseOptions) => {
1291
+ if (!html)
1292
+ return '';
1293
+ const doc = nodeHtmlParser.parse(html, parseOptions);
1294
+ return decodeHTMLEntities(doc.innerText);
1421
1295
  };
1422
- const removeDuplicates = (sections) => {
1423
- const map = new Map();
1424
- sections.forEach((s) => {
1425
- if (isReference(s)) {
1426
- map.set(`${s.referent.id}${s.referent.website}`, s);
1427
- }
1428
- else {
1429
- map.set(`${s._id}${s._website}`, s);
1430
- }
1431
- });
1432
- return [...map.values()];
1296
+ const getHTMLElementAttribute = (e, key) => {
1297
+ const value = e.getAttribute(key);
1298
+ if (value)
1299
+ return value;
1300
+ return new URLSearchParams(e.rawAttrs.replaceAll(' ', '&')).get(key);
1433
1301
  };
1434
- class SectionsRepository {
1435
- constructor(arc) {
1436
- this.arc = arc;
1437
- this.sectionsByWebsite = {};
1438
- this.websitesAreLoaded = false;
1439
- }
1440
- async put(ans) {
1441
- await this.arc.Site.putSection(ans);
1442
- const created = await this.arc.Site.getSection(ans._id, ans.website);
1443
- this.save(created);
1444
- }
1445
- async loadWebsite(website) {
1446
- const sections = [];
1447
- let next = true;
1448
- let offset = 0;
1449
- while (next) {
1450
- const migrated = await this.arc.Site.getSections({ website, offset }).catch((_) => {
1451
- return { q_results: [] };
1452
- });
1453
- if (migrated.q_results.length) {
1454
- sections.push(...migrated.q_results);
1455
- offset += migrated.q_results.length;
1456
- }
1457
- else {
1458
- next = false;
1459
- }
1460
- }
1461
- return sections;
1462
- }
1463
- async loadWebsites(websites) {
1464
- for (const website of websites) {
1465
- this.sectionsByWebsite[website] = await this.loadWebsite(website);
1466
- }
1467
- this.websitesAreLoaded = true;
1468
- }
1469
- save(section) {
1470
- const website = section._website;
1471
- assert.ok(website, 'Section must have a website');
1472
- this.sectionsByWebsite[website] = this.sectionsByWebsite[website] || [];
1473
- if (!this.sectionsByWebsite[website].find((s) => s._id === section._id)) {
1474
- this.sectionsByWebsite[website].push(section);
1475
- }
1476
- }
1477
- getById(id, website) {
1478
- this.ensureWebsitesLoaded();
1479
- const section = this.sectionsByWebsite[website]?.find((s) => s._id === id);
1480
- return section;
1481
- }
1482
- getByWebsite(website) {
1483
- this.ensureWebsitesLoaded();
1484
- return this.sectionsByWebsite[website];
1485
- }
1486
- getParentSections(section) {
1487
- this.ensureWebsitesLoaded();
1488
- const parents = [];
1489
- let current = section;
1490
- while (current.parent?.default && current.parent.default !== '/') {
1491
- const parent = this.getById(current.parent.default, section._website);
1492
- if (!parent)
1493
- break;
1494
- parents.push(parent);
1495
- current = parent;
1496
- }
1497
- return parents;
1498
- }
1499
- ensureWebsitesLoaded() {
1500
- assert.ok(this.websitesAreLoaded, 'call .loadWebsites() first');
1501
- }
1502
- }
1503
1302
 
1504
- var Section = /*#__PURE__*/Object.freeze({
1303
+ var html_utils = /*#__PURE__*/Object.freeze({
1505
1304
  __proto__: null,
1506
- SectionsRepository: SectionsRepository,
1507
- buildAndFlattenTree: buildAndFlattenTree,
1508
- buildTree: buildTree,
1509
- flattenTree: flattenTree,
1510
- groupByWebsites: groupByWebsites,
1511
- isReference: isReference,
1512
- references: references,
1513
- removeDuplicates: removeDuplicates
1305
+ getHTMLElementAttribute: getHTMLElementAttribute,
1306
+ htmlToText: htmlToText,
1307
+ isCommentNode: isCommentNode,
1308
+ isHTMLElement: isHTMLElement,
1309
+ isTextNode: isTextNode,
1310
+ nodeTagIn: nodeTagIn,
1311
+ nodeTagIs: nodeTagIs
1514
1312
  });
1515
1313
 
1516
- const ArcUtils = {
1517
- Id,
1518
- ANS,
1519
- ContentElements,
1520
- Section,
1521
- };
1522
-
1523
1314
  /**
1524
- * Base class for all arc entities, it provides common methods and properties
1525
- * If you want to create a new entity subtype you should extend this class
1315
+ * HTMLProcessor is responsible for parsing HTML content into structured content elements.
1316
+ * It provides a flexible way to handle different HTML nodes and wrap text content.
1526
1317
  *
1527
- * Use case: You want to migrate stories from BBC
1528
- * You define `class BBCStory extends ArcDocument<ANS.AStory>` and implement all abstract methods
1529
- * Then you can override the specific methods to enrich the story with the data from BBC
1318
+ * The processor can be extended with custom handlers for specific node types and
1319
+ * wrappers for text content.
1530
1320
  *
1531
- * To migrate it call .migrate() method
1532
- */
1533
- class Document {
1534
- constructor() {
1535
- this.ans = null;
1536
- this.circulations = [];
1537
- }
1538
- async init() {
1539
- // fetch necessary data and validate it here
1540
- }
1541
- async prepare() {
1542
- await this.init();
1321
+ * @example
1322
+ * ```ts
1323
+ * // Create and initialize processor
1324
+ * const processor = new HTMLProcessor();
1325
+ * processor.init();
1326
+ *
1327
+ * // Parse HTML content
1328
+ * const html = '<div><p>Some text</p><img src="image.jpg"></div>';
1329
+ * const elements = await processor.parse(html);
1330
+ * ```
1331
+ *
1332
+ * The processor comes with built-in handlers for common HTML elements like links,
1333
+ * text formatting (i, u, strong), and block elements. Custom handlers can be added
1334
+ * using the `handle()` and `wrap()` methods.
1335
+ */
1336
+ class HTMLProcessor {
1337
+ constructor() {
1338
+ this.parallelProcessing = true;
1339
+ this.handlers = {
1340
+ node: new Map(),
1341
+ wrap: new Map(),
1342
+ };
1343
+ }
1344
+ init() {
1345
+ // wrappers are used to wrap the content of nested text nodes
1346
+ // in a specific way
1347
+ this.wrap('link', (node, text) => {
1348
+ if (nodeTagIn(node, ['a'])) {
1349
+ const attributes = ['href', 'target', 'rel']
1350
+ .map((attr) => [attr, getHTMLElementAttribute(node, attr)])
1351
+ .filter(([_, value]) => value)
1352
+ .map(([key, value]) => `${key}="${value}"`)
1353
+ .join(' ');
1354
+ return {
1355
+ ...text,
1356
+ content: `<a ${attributes}>${text.content}</a>`,
1357
+ };
1358
+ }
1359
+ });
1360
+ this.wrap('i', (node, text) => {
1361
+ if (nodeTagIn(node, ['i'])) {
1362
+ return {
1363
+ ...text,
1364
+ content: `<i>${text.content}</i>`,
1365
+ };
1366
+ }
1367
+ });
1368
+ this.wrap('u', (node, text) => {
1369
+ if (nodeTagIn(node, ['u'])) {
1370
+ return {
1371
+ ...text,
1372
+ content: `<u>${text.content}</u>`,
1373
+ };
1374
+ }
1375
+ });
1376
+ this.wrap('sup/sub', (node, text) => {
1377
+ if (nodeTagIn(node, ['sup', 'sub'])) {
1378
+ return {
1379
+ ...text,
1380
+ content: `<mark class="${node.tagName.toLowerCase()}">${text.content}</mark>`,
1381
+ };
1382
+ }
1383
+ });
1384
+ this.wrap('strong', (node, text) => {
1385
+ if (nodeTagIn(node, ['strong', 'b'])) {
1386
+ return {
1387
+ ...text,
1388
+ content: `<b>${text.content}</b>`,
1389
+ };
1390
+ }
1391
+ });
1392
+ this.wrap('center', (node, text) => {
1393
+ if (nodeTagIn(node, ['center'])) {
1394
+ return {
1395
+ ...text,
1396
+ alignment: 'center',
1397
+ };
1398
+ }
1399
+ });
1400
+ this.wrap('aligned-paragraph', (node, text) => {
1401
+ if (nodeTagIn(node, ['p'])) {
1402
+ const styleAttribute = getHTMLElementAttribute(node, 'style') || '';
1403
+ if (!styleAttribute)
1404
+ return text;
1405
+ if (styleAttribute.includes('text-align: right;')) {
1406
+ return {
1407
+ ...text,
1408
+ alignment: 'right',
1409
+ };
1410
+ }
1411
+ if (styleAttribute.includes('text-align: left;')) {
1412
+ return {
1413
+ ...text,
1414
+ alignment: 'left',
1415
+ };
1416
+ }
1417
+ if (styleAttribute.includes('text-align: center;')) {
1418
+ return {
1419
+ ...text,
1420
+ alignment: 'center',
1421
+ };
1422
+ }
1423
+ return text;
1424
+ }
1425
+ });
1426
+ // handlers are used to handle specific nodes
1427
+ // and return a list of content elements
1428
+ this.handle('default', (node) => {
1429
+ const noTag = isHTMLElement(node) && !node.tagName;
1430
+ if (noTag ||
1431
+ nodeTagIn(node, [
1432
+ 'p',
1433
+ 'a',
1434
+ 'b',
1435
+ 'sup',
1436
+ 'sub',
1437
+ 'span',
1438
+ 'strong',
1439
+ 'em',
1440
+ 'i',
1441
+ 'u',
1442
+ 'section',
1443
+ 'main',
1444
+ 'div',
1445
+ 'li',
1446
+ 'center',
1447
+ ])) {
1448
+ return this.handleNested(node);
1449
+ }
1450
+ });
1451
+ this.handle('headers', (node) => {
1452
+ if (nodeTagIn(node, ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'])) {
1453
+ return this.createHeader(node);
1454
+ }
1455
+ });
1456
+ this.handle('text', (node) => {
1457
+ if (isTextNode(node)) {
1458
+ return this.createText(node);
1459
+ }
1460
+ });
1461
+ this.handle('comment', (node) => {
1462
+ if (isCommentNode(node)) {
1463
+ return this.handleComment(node);
1464
+ }
1465
+ });
1466
+ this.handle('list', async (node) => {
1467
+ if (nodeTagIn(node, ['ul', 'ol'])) {
1468
+ const listType = node.tagName === 'UL' ? 'unordered' : 'ordered';
1469
+ return this.createList(node, listType);
1470
+ }
1471
+ });
1472
+ this.handle('table', (node) => {
1473
+ if (nodeTagIs(node, 'table')) {
1474
+ return this.handleTable(node);
1475
+ }
1476
+ });
1477
+ this.handle('iframe', (node) => {
1478
+ if (nodeTagIs(node, 'iframe')) {
1479
+ return this.handleIframe(node);
1480
+ }
1481
+ });
1482
+ this.handle('img', (node) => {
1483
+ if (nodeTagIs(node, 'img')) {
1484
+ return this.handleImage(node);
1485
+ }
1486
+ });
1487
+ this.handle('br', (node) => {
1488
+ if (nodeTagIs(node, 'br')) {
1489
+ return this.handleBreak(node);
1490
+ }
1491
+ });
1492
+ }
1493
+ handle(name, handler) {
1494
+ if (this.handlers.node.has(name)) {
1495
+ this.warn({ name }, `${name} node handler already set`);
1496
+ }
1497
+ this.handlers.node.set(name, handler);
1498
+ }
1499
+ wrap(name, handler) {
1500
+ if (this.handlers.wrap.has(name)) {
1501
+ this.warn({ name }, `${name} wrap handler already set`);
1502
+ }
1503
+ this.handlers.wrap.set(name, handler);
1504
+ }
1505
+ async parse(html) {
1506
+ const doc = nodeHtmlParser.parse(html, { comment: true });
1507
+ doc.removeWhitespace();
1508
+ const elements = await this.process(doc);
1509
+ const filtered = elements?.filter((e) => e.type !== 'divider');
1510
+ return filtered || [];
1511
+ }
1512
+ addTextAdditionalProperties(c, parent) {
1513
+ const additionalProperties = c.additional_properties || {};
1514
+ const parentNodeIsBlockElement = this.isBlockElement(parent);
1515
+ c.additional_properties = {
1516
+ ...c.additional_properties,
1517
+ isBlockElement: additionalProperties.isBlockElement || parentNodeIsBlockElement,
1518
+ };
1519
+ return c;
1520
+ }
1521
+ /**
1522
+ * Wraps text content elements with additional properties and handlers.
1523
+ * This method iterates through an array of content elements and applies
1524
+ * wrappers to text elements.
1525
+ *
1526
+ * @param node - The HTML node containing the text elements
1527
+ **/
1528
+ wrapChildrenTextNodes(node, elements) {
1529
+ const wrapped = [];
1530
+ const wrappers = [...this.handlers.wrap.values()];
1531
+ for (const c of elements) {
1532
+ if (!isTextCE(c)) {
1533
+ wrapped.push(c);
1534
+ continue;
1535
+ }
1536
+ this.addTextAdditionalProperties(c, node);
1537
+ const handled = wrappers.map((wrapper) => wrapper(node, c)).find(Boolean);
1538
+ wrapped.push(handled || c);
1539
+ }
1540
+ return wrapped;
1541
+ }
1542
+ /**
1543
+ * Handles nested nodes by processing their children and merging text elements.
1544
+ * This method recursively processes the children of a given HTML node and
1545
+ * returns a list of content elements.
1546
+ *
1547
+ * @param node - The HTML node to process
1548
+ **/
1549
+ async handleNested(node) {
1550
+ const children = await this.processChildNodes(node);
1551
+ const filtered = children.filter(Boolean).flat();
1552
+ const merged = this.mergeParagraphs(filtered);
1553
+ const wrapped = this.wrapChildrenTextNodes(node, merged);
1554
+ return wrapped;
1555
+ }
1556
+ async processChildNodes(node) {
1557
+ if (this.parallelProcessing) {
1558
+ return await Promise.all(node.childNodes.map((child) => this.process(child)));
1559
+ }
1560
+ const children = [];
1561
+ for (const child of node.childNodes) {
1562
+ children.push(await this.process(child));
1563
+ }
1564
+ return children;
1565
+ }
1566
+ /**
1567
+ * Processes a single HTML node and converts it into content elements.
1568
+ * This method iterates through registered node handlers and attempts to process the node.
1569
+ * If a handler successfully processes the node, it returns an array of content elements.
1570
+ *
1571
+ * @param node - The HTML node to process
1572
+ * @returns Promise resolving to an array of content elements, or undefined if node cannot be processed
1573
+ */
1574
+ async process(node) {
1575
+ let isKnownNode = false;
1576
+ const elements = [];
1577
+ for (const [name, handler] of this.handlers.node.entries()) {
1578
+ try {
1579
+ const result = await handler(node);
1580
+ if (result) {
1581
+ // if handler returns an array of elements, it means that the node was handled properly, even if there is no elements inside
1582
+ isKnownNode = true;
1583
+ elements.push(...result);
1584
+ break;
1585
+ }
1586
+ }
1587
+ catch (error) {
1588
+ this.warn({ node: node.toString(), error: error.toString(), name }, 'HandlerError');
1589
+ }
1590
+ }
1591
+ if (isKnownNode)
1592
+ return elements;
1593
+ this.warn({ node: node.toString() }, 'UnknownNodeError');
1594
+ }
1595
+ /**
1596
+ * Merges adjacent text content elements into a single paragraph.
1597
+ * This method iterates through an array of content elements and combines
1598
+ * adjacent text elements into a single paragraph.
1599
+ *
1600
+ * @param items - The array of content elements to merge
1601
+ **/
1602
+ mergeParagraphs(items) {
1603
+ const merged = [];
1604
+ let toMerge = [];
1605
+ const merge = () => {
1606
+ if (!toMerge.length)
1607
+ return;
1608
+ const paragraph = toMerge.reduce((acc, p) => {
1609
+ return {
1610
+ ...p,
1611
+ content: acc.content + p.content,
1612
+ };
1613
+ }, { type: 'text', content: '' });
1614
+ merged.push(paragraph);
1615
+ toMerge = [];
1616
+ };
1617
+ for (let i = 0; i < items.length; i++) {
1618
+ const item = items[i];
1619
+ const isBlockElement = item.additional_properties?.isBlockElement;
1620
+ if (isTextCE(item) && !isBlockElement) {
1621
+ toMerge.push(item);
1622
+ }
1623
+ else {
1624
+ merge();
1625
+ merged.push(item);
1626
+ }
1627
+ }
1628
+ merge();
1629
+ return merged;
1630
+ }
1631
+ handleComment(_) {
1632
+ return [];
1633
+ }
1634
+ async handleTable(node) {
1635
+ return [ContentElement.raw_html(node.toString())];
1636
+ }
1637
+ async handleIframe(node) {
1638
+ return [ContentElement.raw_html(node.toString())];
1639
+ }
1640
+ async handleImage(node) {
1641
+ return [ContentElement.raw_html(node.toString())];
1642
+ }
1643
+ async handleBreak(_) {
1644
+ return [ContentElement.divider()];
1645
+ }
1646
+ async createQuote(node) {
1647
+ const items = await this.handleNested(node);
1648
+ return [ContentElement.quote(items)];
1649
+ }
1650
+ async createText(node) {
1651
+ const text = ContentElement.text(node.text);
1652
+ return [text];
1653
+ }
1654
+ filterListItems(items) {
1655
+ return items.filter((i) => ['text', 'list'].includes(i.type));
1656
+ }
1657
+ async createList(node, type) {
1658
+ const items = await this.handleNested(node);
1659
+ return [ContentElement.list(type, this.filterListItems(items))];
1660
+ }
1661
+ async createHeader(node) {
1662
+ const level = +node.tagName.split('H')[1] || 3;
1663
+ return [ContentElement.header(node.innerText, level)];
1664
+ }
1665
+ isBlockElement(node) {
1666
+ if (!isHTMLElement(node))
1667
+ return false;
1668
+ const defaultBlockElements = new Set(BLOCK_ELEMENT_TAGS);
1669
+ return defaultBlockElements.has(node.tagName);
1670
+ }
1671
+ warn(metadata, message) {
1672
+ console.warn(metadata, message);
1673
+ }
1674
+ }
1675
+
1676
+ var index$3 = /*#__PURE__*/Object.freeze({
1677
+ __proto__: null,
1678
+ Constants: html_constants,
1679
+ HTMLProcessor: HTMLProcessor,
1680
+ Utils: html_utils
1681
+ });
1682
+
1683
+ var index$2 = /*#__PURE__*/Object.freeze({
1684
+ __proto__: null,
1685
+ ContentElement: ContentElement,
1686
+ HTML: index$3
1687
+ });
1688
+
1689
+ /**
1690
+ * Base class for all arc entities, it provides common methods and properties
1691
+ * If you want to create a new entity subtype you should extend this class
1692
+ *
1693
+ * Use case: You want to migrate stories from BBC
1694
+ * You define `class BBCStory extends ArcDocument<ANS.AStory>` and implement all abstract methods
1695
+ * Then you can override the specific methods to enrich the story with the data from BBC
1696
+ *
1697
+ * To migrate it call .migrate() method
1698
+ */
1699
+ class Document {
1700
+ constructor() {
1701
+ this.ans = null;
1702
+ this.circulations = [];
1703
+ }
1704
+ async init() {
1705
+ // fetch necessary data and validate it here
1706
+ }
1707
+ async prepare() {
1708
+ await this.init();
1543
1709
  const payload = await this.payload();
1544
1710
  const params = await this.params();
1545
1711
  return { payload, params };
@@ -1768,480 +1934,314 @@ class Story extends Document {
1768
1934
  }
1769
1935
  }
1770
1936
 
1771
- var index$2 = /*#__PURE__*/Object.freeze({
1937
+ var index$1 = /*#__PURE__*/Object.freeze({
1772
1938
  __proto__: null,
1773
1939
  Document: Document,
1774
1940
  Story: Story
1775
1941
  });
1776
1942
 
1777
- const BLOCK_ELEMENT_TAGS = [
1778
- 'ADDRESS',
1779
- 'ARTICLE',
1780
- 'ASIDE',
1781
- 'BLOCKQUOTE',
1782
- 'DETAILS',
1783
- 'DIV',
1784
- 'DL',
1785
- 'FIELDSET',
1786
- 'FIGCAPTION',
1787
- 'FIGURE',
1788
- 'FOOTER',
1789
- 'FORM',
1790
- 'H1',
1791
- 'H2',
1792
- 'H3',
1793
- 'H4',
1794
- 'H5',
1795
- 'H6',
1796
- 'HEADER',
1797
- 'HR',
1798
- 'LINE',
1799
- 'MAIN',
1800
- 'MENU',
1801
- 'NAV',
1802
- 'OL',
1803
- 'P',
1804
- 'PARAGRAPH',
1805
- 'PRE',
1806
- 'SECTION',
1807
- 'TABLE',
1808
- 'UL',
1809
- 'LI',
1810
- 'BODY',
1811
- 'HTML',
1812
- ];
1943
+ var ANSType;
1944
+ (function (ANSType) {
1945
+ ANSType["Story"] = "story";
1946
+ ANSType["Video"] = "video";
1947
+ ANSType["Tag"] = "tag";
1948
+ ANSType["Author"] = "author";
1949
+ ANSType["Gallery"] = "gallery";
1950
+ ANSType["Image"] = "image";
1951
+ ANSType["Redirect"] = "redirect";
1952
+ })(ANSType || (ANSType = {}));
1953
+ var MigrationStatus;
1954
+ (function (MigrationStatus) {
1955
+ MigrationStatus["Success"] = "Success";
1956
+ MigrationStatus["Queued"] = "Queued";
1957
+ MigrationStatus["Circulated"] = "Circulated";
1958
+ MigrationStatus["Published"] = "Published";
1959
+ MigrationStatus["Scheduled"] = "Scheduled";
1960
+ MigrationStatus["FailVideo"] = "FailVideo";
1961
+ MigrationStatus["FailImage"] = "FailImage";
1962
+ MigrationStatus["FailPhoto"] = "FailPhoto";
1963
+ MigrationStatus["FailStory"] = "FailStory";
1964
+ MigrationStatus["FailGallery"] = "FailGallery";
1965
+ MigrationStatus["FailAuthor"] = "FailAuthor";
1966
+ MigrationStatus["FailTag"] = "FailTag";
1967
+ MigrationStatus["ValidationFailed"] = "ValidationFailed";
1968
+ })(MigrationStatus || (MigrationStatus = {}));
1969
+ var SummarySortBy;
1970
+ (function (SummarySortBy) {
1971
+ SummarySortBy["CreateDate"] = "createDate";
1972
+ SummarySortBy["UpdateDate"] = "updateDate";
1973
+ SummarySortBy["Id"] = "id";
1974
+ })(SummarySortBy || (SummarySortBy = {}));
1975
+ var SummarySortOrder;
1976
+ (function (SummarySortOrder) {
1977
+ SummarySortOrder["ASC"] = "ASC";
1978
+ SummarySortOrder["DESC"] = "DESC";
1979
+ })(SummarySortOrder || (SummarySortOrder = {}));
1813
1980
 
1814
- var html_constants = /*#__PURE__*/Object.freeze({
1981
+ /* eslint-disable */
1982
+ /**
1983
+ * This file was automatically generated by json-schema-to-typescript.
1984
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
1985
+ * and run json-schema-to-typescript to regenerate this file.
1986
+ */
1987
+
1988
+ var ansTypes = /*#__PURE__*/Object.freeze({
1989
+ __proto__: null
1990
+ });
1991
+
1992
+ var utils = /*#__PURE__*/Object.freeze({
1993
+ __proto__: null
1994
+ });
1995
+
1996
+ var index = /*#__PURE__*/Object.freeze({
1815
1997
  __proto__: null,
1816
- BLOCK_ELEMENT_TAGS: BLOCK_ELEMENT_TAGS
1998
+ ANS: ansTypes,
1999
+ get ANSType () { return ANSType; },
2000
+ get MigrationStatus () { return MigrationStatus; },
2001
+ get SummarySortBy () { return SummarySortBy; },
2002
+ get SummarySortOrder () { return SummarySortOrder; },
2003
+ TypeUtils: utils
1817
2004
  });
1818
2005
 
1819
- const isTextNode = (node) => {
1820
- return node instanceof nodeHtmlParser.TextNode;
1821
- };
1822
- const isHTMLElement = (node) => {
1823
- return node instanceof nodeHtmlParser.HTMLElement;
1824
- };
1825
- const isCommentNode = (node) => {
1826
- return node instanceof nodeHtmlParser.CommentNode;
1827
- };
1828
- const nodeTagIs = (node, name) => {
1829
- return isHTMLElement(node) && node.tagName?.toLowerCase() === name.toLowerCase();
1830
- };
1831
- const nodeTagIn = (node, names) => {
1832
- return isHTMLElement(node) && names.includes(node.tagName?.toLowerCase());
1833
- };
1834
- const isTextCE = (ce) => {
1835
- return ce?.type === 'text';
1836
- };
1837
- const decodeHTMLEntities = (str) => htmlEntities.decode(str);
1838
- const htmlToText = (html, parseOptions) => {
1839
- if (!html)
1840
- return '';
1841
- const doc = nodeHtmlParser.parse(html, parseOptions);
1842
- return decodeHTMLEntities(doc.innerText);
1843
- };
1844
- const getHTMLElementAttribute = (e, key) => {
1845
- const value = e.getAttribute(key);
1846
- if (value)
1847
- return value;
1848
- return new URLSearchParams(e.rawAttrs.replaceAll(' ', '&')).get(key);
2006
+ const reference = (ref) => {
2007
+ return {
2008
+ _id: ref.id,
2009
+ type: 'reference',
2010
+ referent: {
2011
+ ...ref,
2012
+ },
2013
+ };
1849
2014
  };
1850
2015
 
1851
- var html_utils = /*#__PURE__*/Object.freeze({
2016
+ var ANS = /*#__PURE__*/Object.freeze({
1852
2017
  __proto__: null,
1853
- decodeHTMLEntities: decodeHTMLEntities,
1854
- getHTMLElementAttribute: getHTMLElementAttribute,
1855
- htmlToText: htmlToText,
1856
- isCommentNode: isCommentNode,
1857
- isHTMLElement: isHTMLElement,
1858
- isTextCE: isTextCE,
1859
- isTextNode: isTextNode,
1860
- nodeTagIn: nodeTagIn,
1861
- nodeTagIs: nodeTagIs
2018
+ reference: reference
1862
2019
  });
1863
2020
 
2021
+ const generateArcId = (identifier, orgHostname) => {
2022
+ const namespace = uuid.v5(orgHostname, uuid.v5.DNS);
2023
+ const buffer = uuid.v5(identifier, namespace, Buffer.alloc(16));
2024
+ return encode(buffer, 'RFC4648', { padding: false });
2025
+ };
1864
2026
  /**
1865
- * HTMLProcessor is responsible for parsing HTML content into structured content elements.
1866
- * It provides a flexible way to handle different HTML nodes and wrap text content.
1867
- *
1868
- * The processor can be extended with custom handlers for specific node types and
1869
- * wrappers for text content.
2027
+ * Utility class for generating Arc IDs and source IDs
1870
2028
  *
1871
2029
  * @example
1872
2030
  * ```ts
1873
- * // Create and initialize processor
1874
- * const processor = new HTMLProcessor();
1875
- * processor.init();
1876
- *
1877
- * // Parse HTML content
1878
- * const html = '<div><p>Some text</p><img src="image.jpg"></div>';
1879
- * const elements = await processor.parse(html);
2031
+ * const generator = new IdGenerator(['my-org']);
2032
+ * const arcId = generator.getArcId('123'); // Generates a unique for 'my-org' Arc ID
2033
+ * const sourceId = generator.getSourceId('123', ['my-site']); // Generates 'my-site-123'
1880
2034
  * ```
1881
- *
1882
- * The processor comes with built-in handlers for common HTML elements like links,
1883
- * text formatting (i, u, strong), and block elements. Custom handlers can be added
1884
- * using the `handle()` and `wrap()` methods.
1885
2035
  */
1886
- class HTMLProcessor {
1887
- constructor() {
1888
- this.parallelProcessing = true;
1889
- this.handlers = {
1890
- node: new Map(),
1891
- wrap: new Map(),
1892
- };
1893
- }
1894
- init() {
1895
- // wrappers are used to wrap the content of nested text nodes
1896
- // in a specific way
1897
- this.wrap('link', (node, text) => {
1898
- if (nodeTagIn(node, ['a'])) {
1899
- const attributes = ['href', 'target', 'rel']
1900
- .map((attr) => [attr, getHTMLElementAttribute(node, attr)])
1901
- .filter(([_, value]) => value)
1902
- .map(([key, value]) => `${key}="${value}"`)
1903
- .join(' ');
1904
- return {
1905
- ...text,
1906
- content: `<a ${attributes}>${text.content}</a>`,
1907
- };
1908
- }
1909
- });
1910
- this.wrap('i', (node, text) => {
1911
- if (nodeTagIn(node, ['i'])) {
1912
- return {
1913
- ...text,
1914
- content: `<i>${text.content}</i>`,
1915
- };
1916
- }
1917
- });
1918
- this.wrap('u', (node, text) => {
1919
- if (nodeTagIn(node, ['u'])) {
1920
- return {
1921
- ...text,
1922
- content: `<u>${text.content}</u>`,
1923
- };
1924
- }
1925
- });
1926
- this.wrap('sup/sub', (node, text) => {
1927
- if (nodeTagIn(node, ['sup', 'sub'])) {
1928
- return {
1929
- ...text,
1930
- content: `<mark class="${node.tagName.toLowerCase()}">${text.content}</mark>`,
1931
- };
1932
- }
1933
- });
1934
- this.wrap('strong', (node, text) => {
1935
- if (nodeTagIn(node, ['strong', 'b'])) {
1936
- return {
1937
- ...text,
1938
- content: `<b>${text.content}</b>`,
1939
- };
1940
- }
1941
- });
1942
- this.wrap('center', (node, text) => {
1943
- if (nodeTagIn(node, ['center'])) {
1944
- return {
1945
- ...text,
1946
- alignment: 'center',
1947
- };
1948
- }
1949
- });
1950
- this.wrap('aligned-paragraph', (node, text) => {
1951
- if (nodeTagIn(node, ['p'])) {
1952
- const styleAttribute = getHTMLElementAttribute(node, 'style') || '';
1953
- if (!styleAttribute)
1954
- return text;
1955
- if (styleAttribute.includes('text-align: right;')) {
1956
- return {
1957
- ...text,
1958
- alignment: 'right',
1959
- };
1960
- }
1961
- if (styleAttribute.includes('text-align: left;')) {
1962
- return {
1963
- ...text,
1964
- alignment: 'left',
1965
- };
1966
- }
1967
- if (styleAttribute.includes('text-align: center;')) {
1968
- return {
1969
- ...text,
1970
- alignment: 'center',
1971
- };
1972
- }
1973
- return text;
1974
- }
1975
- });
1976
- // handlers are used to handle specific nodes
1977
- // and return a list of content elements
1978
- this.handle('default', (node) => {
1979
- const noTag = isHTMLElement(node) && !node.tagName;
1980
- if (noTag ||
1981
- nodeTagIn(node, [
1982
- 'p',
1983
- 'a',
1984
- 'b',
1985
- 'sup',
1986
- 'sub',
1987
- 'span',
1988
- 'strong',
1989
- 'em',
1990
- 'i',
1991
- 'u',
1992
- 'section',
1993
- 'main',
1994
- 'div',
1995
- 'li',
1996
- 'center',
1997
- ])) {
1998
- return this.handleNested(node);
1999
- }
2000
- });
2001
- this.handle('headers', (node) => {
2002
- if (nodeTagIn(node, ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'])) {
2003
- return this.createHeader(node);
2004
- }
2005
- });
2006
- this.handle('text', (node) => {
2007
- if (isTextNode(node)) {
2008
- return this.createText(node);
2009
- }
2010
- });
2011
- this.handle('comment', (node) => {
2012
- if (isCommentNode(node)) {
2013
- return this.handleComment(node);
2014
- }
2015
- });
2016
- this.handle('list', async (node) => {
2017
- if (nodeTagIn(node, ['ul', 'ol'])) {
2018
- const listType = node.tagName === 'UL' ? 'unordered' : 'ordered';
2019
- return this.createList(node, listType);
2020
- }
2021
- });
2022
- this.handle('table', (node) => {
2023
- if (nodeTagIs(node, 'table')) {
2024
- return this.handleTable(node);
2025
- }
2026
- });
2027
- this.handle('iframe', (node) => {
2028
- if (nodeTagIs(node, 'iframe')) {
2029
- return this.handleIframe(node);
2030
- }
2031
- });
2032
- this.handle('img', (node) => {
2033
- if (nodeTagIs(node, 'img')) {
2034
- return this.handleImage(node);
2035
- }
2036
- });
2037
- this.handle('br', (node) => {
2038
- if (nodeTagIs(node, 'br')) {
2039
- return this.handleBreak(node);
2040
- }
2041
- });
2042
- }
2043
- handle(name, handler) {
2044
- if (this.handlers.node.has(name)) {
2045
- this.warn({ name }, `${name} node handler already set`);
2036
+ class IdGenerator {
2037
+ constructor(namespaces) {
2038
+ if (!namespaces.length) {
2039
+ throw new Error('At least 1 namespace is required');
2046
2040
  }
2047
- this.handlers.node.set(name, handler);
2041
+ this.namespace = namespaces.join('-');
2048
2042
  }
2049
- wrap(name, handler) {
2050
- if (this.handlers.wrap.has(name)) {
2051
- this.warn({ name }, `${name} wrap handler already set`);
2052
- }
2053
- this.handlers.wrap.set(name, handler);
2043
+ getArcId(id) {
2044
+ return generateArcId(id.toString(), this.namespace);
2054
2045
  }
2055
- async parse(html) {
2056
- const doc = nodeHtmlParser.parse(html, { comment: true });
2057
- doc.removeWhitespace();
2058
- const elements = await this.process(doc);
2059
- const filtered = elements?.filter((e) => e.type !== 'divider');
2060
- return filtered || [];
2046
+ getSourceId(id, prefixes = []) {
2047
+ return [...prefixes, id].join('-');
2061
2048
  }
2062
- addTextAdditionalProperties(c, parent) {
2063
- const additionalProperties = c.additional_properties || {};
2064
- const parentNodeIsBlockElement = this.isBlockElement(parent);
2065
- c.additional_properties = {
2066
- ...c.additional_properties,
2067
- isBlockElement: additionalProperties.isBlockElement || parentNodeIsBlockElement,
2049
+ }
2050
+
2051
+ var Id = /*#__PURE__*/Object.freeze({
2052
+ __proto__: null,
2053
+ IdGenerator: IdGenerator,
2054
+ generateArcId: generateArcId
2055
+ });
2056
+
2057
+ const buildTree = (items) => {
2058
+ const tree = [
2059
+ {
2060
+ id: '/',
2061
+ children: [],
2062
+ meta: new Proxy({}, {
2063
+ get: () => {
2064
+ throw new Error('Root node meta is not accessible');
2065
+ },
2066
+ }),
2067
+ parent: null,
2068
+ },
2069
+ ];
2070
+ // Track nodes at each level to maintain parent-child relationships
2071
+ // stores last node at each level
2072
+ const currLevelNodes = {
2073
+ 0: tree[0],
2074
+ };
2075
+ for (const item of items) {
2076
+ const node = {
2077
+ id: item.id,
2078
+ parent: null,
2079
+ children: [],
2080
+ meta: item,
2068
2081
  };
2069
- return c;
2070
- }
2071
- /**
2072
- * Wraps text content elements with additional properties and handlers.
2073
- * This method iterates through an array of content elements and applies
2074
- * wrappers to text elements.
2075
- *
2076
- * @param node - The HTML node containing the text elements
2077
- **/
2078
- wrapChildrenTextNodes(node, elements) {
2079
- const wrapped = [];
2080
- const wrappers = [...this.handlers.wrap.values()];
2081
- for (const c of elements) {
2082
- if (!isTextCE(c)) {
2083
- wrapped.push(c);
2084
- continue;
2085
- }
2086
- this.addTextAdditionalProperties(c, node);
2087
- const handled = wrappers.map((wrapper) => wrapper(node, c)).find(Boolean);
2088
- wrapped.push(handled || c);
2082
+ // Determine the level of this node
2083
+ const levelKey = Object.keys(item).find((key) => key.startsWith('N') && item[key]);
2084
+ const level = Number(levelKey?.replace('N', '')) || 0;
2085
+ if (!level) {
2086
+ throw new Error(`Invalid level for section ${item.id}`);
2089
2087
  }
2090
- return wrapped;
2088
+ // This is a child node - attach to its parent
2089
+ const parentLevel = level - 1;
2090
+ const parentNode = currLevelNodes[parentLevel];
2091
+ if (parentNode) {
2092
+ node.parent = parentNode;
2093
+ parentNode.children.push(node);
2094
+ }
2095
+ else {
2096
+ throw new Error(`Parent node not found for section ${item.id}`);
2097
+ }
2098
+ // Set this as the current node for its level
2099
+ currLevelNodes[level] = node;
2091
2100
  }
2092
- /**
2093
- * Handles nested nodes by processing their children and merging text elements.
2094
- * This method recursively processes the children of a given HTML node and
2095
- * returns a list of content elements.
2096
- *
2097
- * @param node - The HTML node to process
2098
- **/
2099
- async handleNested(node) {
2100
- const children = await this.processChildNodes(node);
2101
- const filtered = children.filter(Boolean).flat();
2102
- const merged = this.mergeParagraphs(filtered);
2103
- const wrapped = this.wrapChildrenTextNodes(node, merged);
2104
- return wrapped;
2101
+ // return root nodes children
2102
+ return tree[0].children;
2103
+ };
2104
+ const flattenTree = (tree) => {
2105
+ const flatten = [];
2106
+ const traverse = (node) => {
2107
+ flatten.push(node);
2108
+ for (const child of node.children) {
2109
+ traverse(child);
2110
+ }
2111
+ };
2112
+ // traverse all root nodes and their children
2113
+ for (const node of tree) {
2114
+ traverse(node);
2105
2115
  }
2106
- async processChildNodes(node) {
2107
- if (this.parallelProcessing) {
2108
- return await Promise.all(node.childNodes.map((child) => this.process(child)));
2116
+ return flatten;
2117
+ };
2118
+ const buildAndFlattenTree = (items) => flattenTree(buildTree(items));
2119
+ const groupByWebsites = (sections) => {
2120
+ return sections.reduce((acc, section) => {
2121
+ const website = section._website;
2122
+ if (!acc[website])
2123
+ acc[website] = [];
2124
+ acc[website].push(section);
2125
+ return acc;
2126
+ }, {});
2127
+ };
2128
+ const references = (sections) => {
2129
+ return sections.map((s) => reference({
2130
+ id: s._id,
2131
+ website: s._website,
2132
+ type: 'section',
2133
+ }));
2134
+ };
2135
+ const isReference = (section) => {
2136
+ return section?.type === 'reference' && section?.referent?.type === 'section';
2137
+ };
2138
+ const removeDuplicates = (sections) => {
2139
+ const map = new Map();
2140
+ sections.forEach((s) => {
2141
+ if (isReference(s)) {
2142
+ map.set(`${s.referent.id}${s.referent.website}`, s);
2109
2143
  }
2110
- const children = [];
2111
- for (const child of node.childNodes) {
2112
- children.push(await this.process(child));
2144
+ else {
2145
+ map.set(`${s._id}${s._website}`, s);
2113
2146
  }
2114
- return children;
2147
+ });
2148
+ return [...map.values()];
2149
+ };
2150
+ class SectionsRepository {
2151
+ constructor(arc) {
2152
+ this.arc = arc;
2153
+ this.sectionsByWebsite = {};
2154
+ this.websitesAreLoaded = false;
2115
2155
  }
2116
- /**
2117
- * Processes a single HTML node and converts it into content elements.
2118
- * This method iterates through registered node handlers and attempts to process the node.
2119
- * If a handler successfully processes the node, it returns an array of content elements.
2120
- *
2121
- * @param node - The HTML node to process
2122
- * @returns Promise resolving to an array of content elements, or undefined if node cannot be processed
2123
- */
2124
- async process(node) {
2125
- let isKnownNode = false;
2126
- const elements = [];
2127
- for (const [name, handler] of this.handlers.node.entries()) {
2128
- try {
2129
- const result = await handler(node);
2130
- if (result) {
2131
- // if handler returns an array of elements, it means that the node was handled properly, even if there is no elements inside
2132
- isKnownNode = true;
2133
- elements.push(...result);
2134
- break;
2135
- }
2136
- }
2137
- catch (error) {
2138
- this.warn({ node: node.toString(), error: error.toString(), name }, 'HandlerError');
2139
- }
2140
- }
2141
- if (isKnownNode)
2142
- return elements;
2143
- this.warn({ node: node.toString() }, 'UnknownNodeError');
2156
+ async put(ans) {
2157
+ await this.arc.Site.putSection(ans);
2158
+ const created = await this.arc.Site.getSection(ans._id, ans.website);
2159
+ this.save(created);
2144
2160
  }
2145
- /**
2146
- * Merges adjacent text content elements into a single paragraph.
2147
- * This method iterates through an array of content elements and combines
2148
- * adjacent text elements into a single paragraph.
2149
- *
2150
- * @param items - The array of content elements to merge
2151
- **/
2152
- mergeParagraphs(items) {
2153
- const merged = [];
2154
- let toMerge = [];
2155
- const merge = () => {
2156
- if (!toMerge.length)
2157
- return;
2158
- const paragraph = toMerge.reduce((acc, p) => {
2159
- return {
2160
- ...p,
2161
- content: acc.content + p.content,
2162
- };
2163
- }, { type: 'text', content: '' });
2164
- merged.push(paragraph);
2165
- toMerge = [];
2166
- };
2167
- for (let i = 0; i < items.length; i++) {
2168
- const item = items[i];
2169
- const isBlockElement = item.additional_properties?.isBlockElement;
2170
- if (isTextCE(item) && !isBlockElement) {
2171
- toMerge.push(item);
2161
+ async loadWebsite(website) {
2162
+ const sections = [];
2163
+ let next = true;
2164
+ let offset = 0;
2165
+ while (next) {
2166
+ const migrated = await this.arc.Site.getSections({ website, offset }).catch((_) => {
2167
+ return { q_results: [] };
2168
+ });
2169
+ if (migrated.q_results.length) {
2170
+ sections.push(...migrated.q_results);
2171
+ offset += migrated.q_results.length;
2172
2172
  }
2173
2173
  else {
2174
- merge();
2175
- merged.push(item);
2174
+ next = false;
2176
2175
  }
2177
2176
  }
2178
- merge();
2179
- return merged;
2180
- }
2181
- handleComment(_) {
2182
- return [];
2183
- }
2184
- async handleTable(node) {
2185
- return [ContentElement.raw_html(node.toString())];
2186
- }
2187
- async handleIframe(node) {
2188
- return [ContentElement.raw_html(node.toString())];
2189
- }
2190
- async handleImage(node) {
2191
- return [ContentElement.raw_html(node.toString())];
2192
- }
2193
- async handleBreak(_) {
2194
- return [ContentElement.divider()];
2195
- }
2196
- async createQuote(node) {
2197
- const items = await this.handleNested(node);
2198
- return [ContentElement.quote(items)];
2177
+ return sections;
2199
2178
  }
2200
- async createText(node) {
2201
- const text = ContentElement.text(node.text);
2202
- return [text];
2179
+ async loadWebsites(websites) {
2180
+ for (const website of websites) {
2181
+ this.sectionsByWebsite[website] = await this.loadWebsite(website);
2182
+ }
2183
+ this.websitesAreLoaded = true;
2203
2184
  }
2204
- filterListItems(items) {
2205
- return items.filter((i) => ['text', 'list'].includes(i.type));
2185
+ save(section) {
2186
+ const website = section._website;
2187
+ assert.ok(website, 'Section must have a website');
2188
+ this.sectionsByWebsite[website] = this.sectionsByWebsite[website] || [];
2189
+ if (!this.sectionsByWebsite[website].find((s) => s._id === section._id)) {
2190
+ this.sectionsByWebsite[website].push(section);
2191
+ }
2206
2192
  }
2207
- async createList(node, type) {
2208
- const items = await this.handleNested(node);
2209
- return [ContentElement.list(type, this.filterListItems(items))];
2193
+ getById(id, website) {
2194
+ this.ensureWebsitesLoaded();
2195
+ const section = this.sectionsByWebsite[website]?.find((s) => s._id === id);
2196
+ return section;
2210
2197
  }
2211
- async createHeader(node) {
2212
- const level = +node.tagName.split('H')[1] || 3;
2213
- return [ContentElement.header(node.innerText, level)];
2198
+ getByWebsite(website) {
2199
+ this.ensureWebsitesLoaded();
2200
+ return this.sectionsByWebsite[website];
2214
2201
  }
2215
- isBlockElement(node) {
2216
- if (!isHTMLElement(node))
2217
- return false;
2218
- const defaultBlockElements = new Set(BLOCK_ELEMENT_TAGS);
2219
- return defaultBlockElements.has(node.tagName);
2202
+ getParentSections(section) {
2203
+ this.ensureWebsitesLoaded();
2204
+ const parents = [];
2205
+ let current = section;
2206
+ while (current.parent?.default && current.parent.default !== '/') {
2207
+ const parent = this.getById(current.parent.default, section._website);
2208
+ if (!parent)
2209
+ break;
2210
+ parents.push(parent);
2211
+ current = parent;
2212
+ }
2213
+ return parents;
2220
2214
  }
2221
- warn(metadata, message) {
2222
- console.warn(metadata, message);
2215
+ ensureWebsitesLoaded() {
2216
+ assert.ok(this.websitesAreLoaded, 'call .loadWebsites() first');
2223
2217
  }
2224
2218
  }
2225
2219
 
2226
- var index$1 = /*#__PURE__*/Object.freeze({
2220
+ var Section = /*#__PURE__*/Object.freeze({
2227
2221
  __proto__: null,
2228
- Constants: html_constants,
2229
- HTMLProcessor: HTMLProcessor,
2230
- Utils: html_utils
2222
+ SectionsRepository: SectionsRepository,
2223
+ buildAndFlattenTree: buildAndFlattenTree,
2224
+ buildTree: buildTree,
2225
+ flattenTree: flattenTree,
2226
+ groupByWebsites: groupByWebsites,
2227
+ isReference: isReference,
2228
+ references: references,
2229
+ removeDuplicates: removeDuplicates
2231
2230
  });
2232
2231
 
2233
- var index = /*#__PURE__*/Object.freeze({
2234
- __proto__: null,
2235
- ContentElement: ContentElement,
2236
- HTML: index$1
2237
- });
2232
+ const ArcUtils = {
2233
+ Id,
2234
+ ANS,
2235
+ ContentElements,
2236
+ Section,
2237
+ };
2238
2238
 
2239
- exports.AnsMapper = index$2;
2239
+ exports.AnsMapper = index$1;
2240
2240
  exports.ArcAPI = ArcAPI;
2241
2241
  exports.ArcError = ArcError;
2242
- exports.ArcTypes = index$3;
2242
+ exports.ArcTypes = index;
2243
2243
  exports.ArcUtils = ArcUtils;
2244
- exports.ContentElements = index;
2244
+ exports.ContentElements = index$2;
2245
2245
  exports.WsClient = WsClient;
2246
2246
  exports.default = ArcAPI;
2247
2247
  //# sourceMappingURL=index.cjs.map