@wdprlib/parser 4.0.0 → 4.2.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.
Files changed (26) hide show
  1. package/README.md +9 -1
  2. package/dist/index.cjs +345 -64
  3. package/dist/index.d.cts +121 -2
  4. package/dist/index.d.ts +121 -2
  5. package/dist/index.js +317 -36
  6. package/package.json +2 -2
  7. package/src/index.ts +9 -0
  8. package/src/parser/rules/block/module/index.ts +10 -0
  9. package/src/parser/rules/block/module/listpages/extract.ts +9 -0
  10. package/src/parser/rules/block/module/listpages/extraction/tagcloud.ts +25 -0
  11. package/src/parser/rules/block/module/listpages/types/data-requirements.ts +2 -0
  12. package/src/parser/rules/block/module/listpages/url-resolution/fields.ts +4 -4
  13. package/src/parser/rules/block/module/listpages/url-resolution/params.ts +12 -1
  14. package/src/parser/rules/block/module/listpages/url-resolution/resolve.ts +10 -1
  15. package/src/parser/rules/block/module/listpages/url-resolution/value.ts +13 -4
  16. package/src/parser/rules/block/module/mapping.ts +2 -0
  17. package/src/parser/rules/block/module/resolution/contexts.ts +29 -1
  18. package/src/parser/rules/block/module/resolution/data-maps.ts +17 -0
  19. package/src/parser/rules/block/module/resolution/dynamic-modules.ts +29 -2
  20. package/src/parser/rules/block/module/resolution/walk-resolve.ts +28 -4
  21. package/src/parser/rules/block/module/resolve.ts +11 -1
  22. package/src/parser/rules/block/module/tagcloud/index.ts +15 -0
  23. package/src/parser/rules/block/module/tagcloud/parser.ts +127 -0
  24. package/src/parser/rules/block/module/tagcloud/resolve.ts +173 -0
  25. package/src/parser/rules/block/module/tagcloud/types.ts +85 -0
  26. package/src/parser/rules/block/module/types-common.ts +15 -0
package/dist/index.js CHANGED
@@ -4468,6 +4468,92 @@ var listUsersModuleRule = {
4468
4468
  }
4469
4469
  };
4470
4470
 
4471
+ // packages/parser/src/parser/rules/block/module/tagcloud/parser.ts
4472
+ import { CSS_LENGTH_UNITS } from "@wdprlib/ast";
4473
+ var FONT_SIZE_PATTERN = new RegExp(`^([0-9]+)(${CSS_LENGTH_UNITS.join("|")})$`, "i");
4474
+ var COLOR_PATTERN = /^[0-9]+,[0-9]+,[0-9]+$/;
4475
+ var POSITIVE_INT_PATTERN = /^[0-9]+$/;
4476
+ var ERROR_FONT_FORMAT = "Unsupported format for font size. Use a number followed by a CSS length unit such as px, em or %.";
4477
+ var ERROR_FONT_MISMATCH = "Format for minFontSize and maxFontSize must use the same unit.";
4478
+ var ERROR_COLOR_FORMAT = 'Unsupported color format. Use "RRR,GGG,BBB" for Red,Green,Blue each within 0-255 range.';
4479
+ function errorBlock(message) {
4480
+ return {
4481
+ element: "container",
4482
+ data: {
4483
+ type: "div",
4484
+ attributes: { class: "error-block" },
4485
+ elements: [{ element: "text", data: message }]
4486
+ }
4487
+ };
4488
+ }
4489
+ function parseLimit(value) {
4490
+ if (!value || !POSITIVE_INT_PATTERN.test(value))
4491
+ return 50;
4492
+ const num = Number.parseInt(value, 10);
4493
+ return Number.isSafeInteger(num) && num > 0 ? num : 50;
4494
+ }
4495
+ function normalizeTarget(value) {
4496
+ if (!value)
4497
+ return "/system:page-tags/tag/";
4498
+ let target = value;
4499
+ if (!target.startsWith("/"))
4500
+ target = `/${target}`;
4501
+ if (!target.endsWith("/"))
4502
+ target = `${target}/`;
4503
+ return `${target}tag/`;
4504
+ }
4505
+ function parseColor(value) {
4506
+ const [r = 0, g = 0, b = 0] = value.split(",").map((part) => Number.parseInt(part, 10));
4507
+ return [r, g, b];
4508
+ }
4509
+ var tagCloudModuleRule = {
4510
+ name: "module-tagcloud",
4511
+ acceptsNames: ["tagcloud"],
4512
+ hasBody: false,
4513
+ parse(_ctx, _pos, args) {
4514
+ const maxFontSize = args.maxfontsize;
4515
+ const minFontSize = args.minfontsize;
4516
+ const maxColor = args.maxcolor;
4517
+ const minColor = args.mincolor;
4518
+ let sizeSmall = 100;
4519
+ let sizeBig = 300;
4520
+ let fontSizeUnit = "%";
4521
+ if (maxFontSize && minFontSize) {
4522
+ const maxMatch = FONT_SIZE_PATTERN.exec(maxFontSize);
4523
+ if (!maxMatch)
4524
+ return errorBlock(ERROR_FONT_FORMAT);
4525
+ const maxUnit = maxMatch[2].toLowerCase();
4526
+ const minMatch = FONT_SIZE_PATTERN.exec(minFontSize);
4527
+ if (!minMatch || minMatch[2].toLowerCase() !== maxUnit) {
4528
+ return errorBlock(ERROR_FONT_MISMATCH);
4529
+ }
4530
+ sizeBig = Number.parseInt(maxMatch[1], 10);
4531
+ sizeSmall = Number.parseInt(minMatch[1], 10);
4532
+ fontSizeUnit = maxUnit;
4533
+ }
4534
+ let colorSmall = [128, 128, 192];
4535
+ let colorBig = [64, 64, 128];
4536
+ if (maxColor && minColor) {
4537
+ if (!COLOR_PATTERN.test(maxColor) || !COLOR_PATTERN.test(minColor)) {
4538
+ return errorBlock(ERROR_COLOR_FORMAT);
4539
+ }
4540
+ colorSmall = parseColor(minColor);
4541
+ colorBig = parseColor(maxColor);
4542
+ }
4543
+ return {
4544
+ module: "tag-cloud",
4545
+ "min-font-size": sizeSmall,
4546
+ "max-font-size": sizeBig,
4547
+ "font-size-unit": fontSizeUnit,
4548
+ "min-color": colorSmall,
4549
+ "max-color": colorBig,
4550
+ target: normalizeTarget(args.target),
4551
+ limit: parseLimit(args.limit),
4552
+ category: args.category || null
4553
+ };
4554
+ }
4555
+ };
4556
+
4471
4557
  // packages/parser/src/parser/rules/block/module/mapping.ts
4472
4558
  var MODULE_RULES = [
4473
4559
  rateModuleRule,
@@ -4477,7 +4563,8 @@ var MODULE_RULES = [
4477
4563
  joinModuleRule,
4478
4564
  pageTreeModuleRule,
4479
4565
  listPagesModuleRule,
4480
- listUsersModuleRule
4566
+ listUsersModuleRule,
4567
+ tagCloudModuleRule
4481
4568
  ];
4482
4569
  var moduleRuleMap = new Map;
4483
4570
  for (const rule of MODULE_RULES) {
@@ -5558,18 +5645,130 @@ function extractListUsersModule(listUsers, state, result) {
5558
5645
  result.compiledListUsersTemplates.set(id, compileListUsersTemplate(body));
5559
5646
  }
5560
5647
 
5648
+ // packages/parser/src/parser/rules/block/module/tagcloud/resolve.ts
5649
+ function isTagCloudModule(module) {
5650
+ return module.module === "tag-cloud";
5651
+ }
5652
+ var NO_TAGS_MESSAGE_PREFIX = "It seems you have no tags attached to pages. To attach a tag simply click on the ";
5653
+ var NO_TAGS_MESSAGE_SUFFIX = " button at the bottom of any page.";
5654
+ function rawUrlEncode(value) {
5655
+ return encodeURIComponent(value).replace(/[!'()*]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`);
5656
+ }
5657
+ function selectTags(tags, limit) {
5658
+ return tags.toSorted((a, b) => b.weight - a.weight || compareTags(a.tag, b.tag)).slice(0, limit).toSorted((a, b) => compareTags(a.tag, b.tag));
5659
+ }
5660
+ function compareTags(a, b) {
5661
+ return a < b ? -1 : a > b ? 1 : 0;
5662
+ }
5663
+ function resolveTagCloud(module, data) {
5664
+ if (data.status === "category-not-found") {
5665
+ return [
5666
+ {
5667
+ element: "container",
5668
+ data: {
5669
+ type: "div",
5670
+ attributes: { class: "error-block" },
5671
+ elements: [{ element: "text", data: `Category "${data.category}" can not be found.` }]
5672
+ }
5673
+ }
5674
+ ];
5675
+ }
5676
+ const tags = selectTags(data.tags, module.limit);
5677
+ if (tags.length === 0) {
5678
+ return [noTagsMessage()];
5679
+ }
5680
+ let minWeight = Number.POSITIVE_INFINITY;
5681
+ let maxWeight = Number.NEGATIVE_INFINITY;
5682
+ for (const tag of tags) {
5683
+ if (tag.weight < minWeight)
5684
+ minWeight = tag.weight;
5685
+ if (tag.weight > maxWeight)
5686
+ maxWeight = tag.weight;
5687
+ }
5688
+ const weightRange = maxWeight - minWeight;
5689
+ const categorySuffix = data.category !== null ? `/category/${rawUrlEncode(data.category)}` : "";
5690
+ const anchors = [];
5691
+ for (const tag of tags) {
5692
+ const a = weightRange === 0 ? 0 : (tag.weight - minWeight) / weightRange;
5693
+ const fontSize = interpolate(module["min-font-size"], module["max-font-size"], a);
5694
+ const [r, g, b] = [0, 1, 2].map((i) => interpolate(module["min-color"][i], module["max-color"][i], a));
5695
+ anchors.push({ element: "text", data: `
5696
+ ` });
5697
+ anchors.push({
5698
+ element: "anchor",
5699
+ data: {
5700
+ target: null,
5701
+ attributes: {
5702
+ class: "tag",
5703
+ href: `${module.target}${rawUrlEncode(tag.tag)}${categorySuffix}`,
5704
+ style: `font-size: ${fontSize}${module["font-size-unit"]}; color: rgb(${r}, ${g}, ${b});`
5705
+ },
5706
+ elements: [{ element: "text", data: tag.tag }]
5707
+ }
5708
+ });
5709
+ }
5710
+ anchors.push({ element: "text", data: `
5711
+ ` });
5712
+ return [
5713
+ {
5714
+ element: "container",
5715
+ data: {
5716
+ type: "div",
5717
+ attributes: { class: "pages-tag-cloud-box" },
5718
+ elements: anchors
5719
+ }
5720
+ }
5721
+ ];
5722
+ }
5723
+ function interpolate(min, max, a) {
5724
+ return Math.round(min + (max - min) * a);
5725
+ }
5726
+ function noTagsMessage() {
5727
+ return {
5728
+ element: "container",
5729
+ data: {
5730
+ type: "paragraph",
5731
+ attributes: {},
5732
+ elements: [
5733
+ { element: "text", data: NO_TAGS_MESSAGE_PREFIX },
5734
+ {
5735
+ element: "container",
5736
+ data: {
5737
+ type: "italics",
5738
+ attributes: {},
5739
+ elements: [{ element: "text", data: "tags" }]
5740
+ }
5741
+ },
5742
+ { element: "text", data: NO_TAGS_MESSAGE_SUFFIX }
5743
+ ]
5744
+ }
5745
+ };
5746
+ }
5747
+
5748
+ // packages/parser/src/parser/rules/block/module/listpages/extraction/tagcloud.ts
5749
+ function extractTagCloudModule(tagCloud, state, result) {
5750
+ const id = state.nextId++;
5751
+ result.requirements.tagCloud.push({
5752
+ id,
5753
+ category: tagCloud.category,
5754
+ limit: tagCloud.limit
5755
+ });
5756
+ }
5757
+
5561
5758
  // packages/parser/src/parser/rules/block/module/listpages/extract.ts
5562
5759
  function extractDataRequirements(ast) {
5563
5760
  const result = {
5564
5761
  requirements: {
5565
5762
  listPages: [],
5566
- listUsers: []
5763
+ listUsers: [],
5764
+ tagCloud: []
5567
5765
  },
5568
5766
  compiledListPagesTemplates: new Map,
5569
5767
  compiledListUsersTemplates: new Map
5570
5768
  };
5571
5769
  const listPagesState = { nextId: 0 };
5572
5770
  const listUsersState = { nextId: 0 };
5771
+ const tagCloudState = { nextId: 0 };
5573
5772
  walkElements(ast.elements, (element) => {
5574
5773
  if (element.element !== "module")
5575
5774
  return;
@@ -5577,6 +5776,8 @@ function extractDataRequirements(ast) {
5577
5776
  extractListPagesModule(element.data, listPagesState, result);
5578
5777
  } else if (isListUsersModule(element.data)) {
5579
5778
  extractListUsersModule(element.data, listUsersState, result);
5779
+ } else if (isTagCloudModule(element.data)) {
5780
+ extractTagCloudModule(element.data, tagCloudState, result);
5580
5781
  }
5581
5782
  });
5582
5783
  return result;
@@ -5650,11 +5851,32 @@ function resolveListPages(module, data, compiledTemplate, parse) {
5650
5851
  const items = renderListPagesItems(module, data, compiledTemplate, parse);
5651
5852
  return wrapListPagesResult(module, items, parse);
5652
5853
  }
5854
+ // packages/parser/src/parser/rules/block/module/listpages/url-resolution/fields.ts
5855
+ var URL_RESOLVABLE_FIELDS = [
5856
+ { attr: "offset", queryKey: "offset", type: "number" },
5857
+ { attr: "limit", queryKey: "limit", type: "number" },
5858
+ { attr: "per-page", queryKey: "perPage", type: "number" },
5859
+ { attr: "order", queryKey: "order", type: "string" },
5860
+ { attr: "tags", queryKey: "tags", type: "string", urlAttrs: ["tag"] },
5861
+ { attr: "category", queryKey: "category", type: "string" },
5862
+ { attr: "parent", queryKey: "parent", type: "string" },
5863
+ { attr: "range", queryKey: "range", type: "string" },
5864
+ { attr: "name", queryKey: "name", type: "string" },
5865
+ { attr: "fullname", queryKey: "fullname", type: "string" },
5866
+ { attr: "created-at", queryKey: "createdAt", type: "string" },
5867
+ { attr: "updated-at", queryKey: "updatedAt", type: "string" },
5868
+ { attr: "created-by", queryKey: "createdBy", type: "string" },
5869
+ { attr: "rating", queryKey: "rating", type: "string" },
5870
+ { attr: "votes", queryKey: "votes", type: "string" },
5871
+ { attr: "reverse", queryKey: "reverse", type: "boolean" }
5872
+ ];
5873
+
5653
5874
  // packages/parser/src/parser/rules/block/module/listpages/url-resolution/params.ts
5654
5875
  function parseUrlParams(url) {
5655
5876
  const params = new Map;
5656
5877
  const parts = url.split("/").filter(Boolean);
5657
- for (let i = 1;i < parts.length - 1; i += 2) {
5878
+ const pairStart = isUrlParameter(parts[0]) ? 0 : 1;
5879
+ for (let i = pairStart;i < parts.length - 1; i += 2) {
5658
5880
  const key = parts[i];
5659
5881
  const value = parts[i + 1];
5660
5882
  if (key && value) {
@@ -5663,6 +5885,10 @@ function parseUrlParams(url) {
5663
5885
  }
5664
5886
  return params;
5665
5887
  }
5888
+ var URL_PARAMETER_NAMES = new Set(URL_RESOLVABLE_FIELDS.flatMap((field) => [field.attr, ...field.urlAttrs ?? []]));
5889
+ function isUrlParameter(param) {
5890
+ return param !== undefined && URL_PARAMETER_NAMES.has(param);
5891
+ }
5666
5892
  // packages/parser/src/parser/rules/block/module/listpages/normalization/tags-category.ts
5667
5893
  var TOKEN_SEPARATOR = /[,;\s]+/;
5668
5894
  function parseTags(value) {
@@ -5918,26 +6144,6 @@ function normalizeQuery(query) {
5918
6144
  return result;
5919
6145
  }
5920
6146
 
5921
- // packages/parser/src/parser/rules/block/module/listpages/url-resolution/fields.ts
5922
- var URL_RESOLVABLE_FIELDS = [
5923
- { attr: "offset", queryKey: "offset", type: "number" },
5924
- { attr: "limit", queryKey: "limit", type: "number" },
5925
- { attr: "per-page", queryKey: "perPage", type: "number" },
5926
- { attr: "order", queryKey: "order", type: "string" },
5927
- { attr: "tags", queryKey: "tags", type: "string" },
5928
- { attr: "category", queryKey: "category", type: "string" },
5929
- { attr: "parent", queryKey: "parent", type: "string" },
5930
- { attr: "range", queryKey: "range", type: "string" },
5931
- { attr: "name", queryKey: "name", type: "string" },
5932
- { attr: "fullname", queryKey: "fullname", type: "string" },
5933
- { attr: "created-at", queryKey: "createdAt", type: "string" },
5934
- { attr: "updated-at", queryKey: "updatedAt", type: "string" },
5935
- { attr: "created-by", queryKey: "createdBy", type: "string" },
5936
- { attr: "rating", queryKey: "rating", type: "string" },
5937
- { attr: "votes", queryKey: "votes", type: "string" },
5938
- { attr: "reverse", queryKey: "reverse", type: "boolean" }
5939
- ];
5940
-
5941
6147
  // packages/parser/src/parser/rules/block/module/listpages/url-resolution/query.ts
5942
6148
  function assignResolvedUrlField(query, field, value) {
5943
6149
  switch (field.type) {
@@ -5958,15 +6164,23 @@ function assignResolvedUrlField(query, field, value) {
5958
6164
  }
5959
6165
 
5960
6166
  // packages/parser/src/parser/rules/block/module/listpages/url-resolution/value.ts
5961
- function resolveUrlValue(rawValue, paramName, urlParams, prefix) {
6167
+ function resolveUrlValue(rawValue, paramNames, urlParams, prefix) {
5962
6168
  if (!rawValue)
5963
6169
  return;
5964
6170
  if (!rawValue.startsWith("@URL")) {
5965
6171
  return rawValue;
5966
6172
  }
5967
6173
  const defaultValue = rawValue.includes("|") ? rawValue.split("|")[1] : undefined;
5968
- const actualParamName = prefix ? `${prefix}_${paramName}` : paramName;
5969
- return urlParams.get(actualParamName) ?? defaultValue;
6174
+ for (const paramName of toParamNames(paramNames)) {
6175
+ const actualParamName = prefix ? `${prefix}_${paramName}` : paramName;
6176
+ const value = urlParams.get(actualParamName);
6177
+ if (value !== undefined)
6178
+ return value;
6179
+ }
6180
+ return defaultValue;
6181
+ }
6182
+ function toParamNames(paramNames) {
6183
+ return typeof paramNames === "string" ? [paramNames] : paramNames;
5970
6184
  }
5971
6185
 
5972
6186
  // packages/parser/src/parser/rules/block/module/listpages/url-resolution/resolve.ts
@@ -5977,13 +6191,16 @@ function resolveQuery(requirement, urlParams) {
5977
6191
  const rawValue = rawAttributes[field.attr];
5978
6192
  if (!rawValue)
5979
6193
  continue;
5980
- const resolvedValue = resolveUrlValue(rawValue, field.attr, urlParams, urlAttrPrefix);
6194
+ const resolvedValue = resolveUrlValue(rawValue, getUrlParamNames(field), urlParams, urlAttrPrefix);
5981
6195
  if (resolvedValue === undefined)
5982
6196
  continue;
5983
6197
  assignResolvedUrlField(resolved, field, resolvedValue);
5984
6198
  }
5985
6199
  return resolved;
5986
6200
  }
6201
+ function getUrlParamNames(field) {
6202
+ return field.urlAttrs ? [field.attr, ...field.urlAttrs] : [field.attr];
6203
+ }
5987
6204
  function resolveAndNormalizeQuery(requirement, urlParams) {
5988
6205
  const resolved = resolveQuery(requirement, urlParams);
5989
6206
  return normalizeQuery(resolved);
@@ -6676,6 +6893,16 @@ async function buildListUsersDataMap(dataProvider, requirements) {
6676
6893
  }
6677
6894
  return dataMap;
6678
6895
  }
6896
+ async function buildTagCloudDataMap(dataProvider, requirements) {
6897
+ const dataMap = new Map;
6898
+ for (const req of requirements) {
6899
+ const data = await dataProvider.fetchTagCloud?.(req);
6900
+ if (data) {
6901
+ dataMap.set(req.id, data);
6902
+ }
6903
+ }
6904
+ return dataMap;
6905
+ }
6679
6906
 
6680
6907
  // packages/parser/src/parser/rules/block/module/resolution/contexts.ts
6681
6908
  async function buildListPagesContext(dataProvider, requirements, compiledTemplates, parse, urlPath) {
@@ -6692,6 +6919,16 @@ async function buildListPagesContext(dataProvider, requirements, compiledTemplat
6692
6919
  parse
6693
6920
  };
6694
6921
  }
6922
+ async function buildTagCloudContext(dataProvider, requirements) {
6923
+ if (requirements.length === 0 || !dataProvider.fetchTagCloud) {
6924
+ return null;
6925
+ }
6926
+ const dataMap = await buildTagCloudDataMap(dataProvider, requirements);
6927
+ if (dataMap.size === 0) {
6928
+ return null;
6929
+ }
6930
+ return { dataMap };
6931
+ }
6695
6932
  async function buildListUsersContext(dataProvider, requirements, compiledTemplates, parse) {
6696
6933
  if (requirements.length === 0 || !dataProvider.fetchListUsers) {
6697
6934
  return null;
@@ -6748,10 +6985,27 @@ function resolveDynamicModuleElement(element, ctx, ids) {
6748
6985
  ids: { ...ids, listUsersId: listUsersId + 1 }
6749
6986
  };
6750
6987
  }
6988
+ if (isTagCloudModule(element.data)) {
6989
+ const elements = [];
6990
+ const tagCloudId = ids.tagCloudId;
6991
+ if (ctx.tagCloud) {
6992
+ const moduleData = ctx.tagCloud.dataMap.get(tagCloudId);
6993
+ if (moduleData) {
6994
+ elements.push(...resolveTagCloud(element.data, moduleData));
6995
+ }
6996
+ } else if (!ctx.fetchTagCloudProvided) {
6997
+ elements.push(element);
6998
+ }
6999
+ return {
7000
+ handled: true,
7001
+ elements,
7002
+ ids: { ...ids, tagCloudId: tagCloudId + 1 }
7003
+ };
7004
+ }
6751
7005
  return { handled: false, elements: [element], ids };
6752
7006
  }
6753
7007
  function countDynamicModules(elements) {
6754
- const counts = { listPagesId: 0, listUsersId: 0 };
7008
+ const counts = { listPagesId: 0, listUsersId: 0, tagCloudId: 0 };
6755
7009
  walkElements(elements, (element) => {
6756
7010
  if (element.element !== "module")
6757
7011
  return;
@@ -6759,6 +7013,8 @@ function countDynamicModules(elements) {
6759
7013
  counts.listPagesId++;
6760
7014
  } else if (isListUsersModule2(element.data)) {
6761
7015
  counts.listUsersId++;
7016
+ } else if (isTagCloudModule(element.data)) {
7017
+ counts.tagCloudId++;
6762
7018
  }
6763
7019
  });
6764
7020
  return counts;
@@ -6769,12 +7025,18 @@ function walkAndResolve(elements, ctx) {
6769
7025
  const result = [];
6770
7026
  let listPagesId = ctx.listPagesIdCounter;
6771
7027
  let listUsersId = ctx.listUsersIdCounter;
7028
+ let tagCloudId = ctx.tagCloudIdCounter;
6772
7029
  for (const element of elements) {
6773
- const dynamicModule = resolveDynamicModuleElement(element, ctx, { listPagesId, listUsersId });
7030
+ const dynamicModule = resolveDynamicModuleElement(element, ctx, {
7031
+ listPagesId,
7032
+ listUsersId,
7033
+ tagCloudId
7034
+ });
6774
7035
  if (dynamicModule.handled) {
6775
7036
  result.push(...dynamicModule.elements);
6776
7037
  listPagesId = dynamicModule.ids.listPagesId;
6777
7038
  listUsersId = dynamicModule.ids.listUsersId;
7039
+ tagCloudId = dynamicModule.ids.tagCloudId;
6778
7040
  continue;
6779
7041
  }
6780
7042
  if (isIfTagsElement(element)) {
@@ -6785,21 +7047,25 @@ function walkAndResolve(elements, ctx) {
6785
7047
  const childResult = walkAndResolve(ifTagsData.elements, {
6786
7048
  ...ctx,
6787
7049
  listPagesIdCounter: listPagesId,
6788
- listUsersIdCounter: listUsersId
7050
+ listUsersIdCounter: listUsersId,
7051
+ tagCloudIdCounter: tagCloudId
6789
7052
  });
6790
7053
  result.push(...childResult.elements);
6791
7054
  listPagesId = childResult.nextListPagesId;
6792
7055
  listUsersId = childResult.nextListUsersId;
7056
+ tagCloudId = childResult.nextTagCloudId;
6793
7057
  } else {
6794
7058
  const counts = countDynamicModules(ifTagsData.elements);
6795
7059
  listPagesId += counts.listPagesId;
6796
7060
  listUsersId += counts.listUsersId;
7061
+ tagCloudId += counts.tagCloudId;
6797
7062
  }
6798
7063
  } else {
6799
7064
  const childResult = walkAndResolve(ifTagsData.elements, {
6800
7065
  ...ctx,
6801
7066
  listPagesIdCounter: listPagesId,
6802
- listUsersIdCounter: listUsersId
7067
+ listUsersIdCounter: listUsersId,
7068
+ tagCloudIdCounter: tagCloudId
6803
7069
  });
6804
7070
  result.push({
6805
7071
  element: "if-tags",
@@ -6810,28 +7076,37 @@ function walkAndResolve(elements, ctx) {
6810
7076
  });
6811
7077
  listPagesId = childResult.nextListPagesId;
6812
7078
  listUsersId = childResult.nextListUsersId;
7079
+ tagCloudId = childResult.nextTagCloudId;
6813
7080
  }
6814
7081
  continue;
6815
7082
  }
6816
- const mapped = mapElementChildrenWithState(element, { listPagesId, listUsersId }, (children, state) => {
7083
+ const mapped = mapElementChildrenWithState(element, { listPagesId, listUsersId, tagCloudId }, (children, state) => {
6817
7084
  const childResult = walkAndResolve(children, {
6818
7085
  ...ctx,
6819
7086
  listPagesIdCounter: state.listPagesId,
6820
- listUsersIdCounter: state.listUsersId
7087
+ listUsersIdCounter: state.listUsersId,
7088
+ tagCloudIdCounter: state.tagCloudId
6821
7089
  });
6822
7090
  return {
6823
7091
  elements: childResult.elements,
6824
7092
  state: {
6825
7093
  listPagesId: childResult.nextListPagesId,
6826
- listUsersId: childResult.nextListUsersId
7094
+ listUsersId: childResult.nextListUsersId,
7095
+ tagCloudId: childResult.nextTagCloudId
6827
7096
  }
6828
7097
  };
6829
7098
  });
6830
7099
  result.push(mapped.element);
6831
7100
  listPagesId = mapped.state.listPagesId;
6832
7101
  listUsersId = mapped.state.listUsersId;
7102
+ tagCloudId = mapped.state.tagCloudId;
6833
7103
  }
6834
- return { elements: result, nextListPagesId: listPagesId, nextListUsersId: listUsersId };
7104
+ return {
7105
+ elements: result,
7106
+ nextListPagesId: listPagesId,
7107
+ nextListUsersId: listUsersId,
7108
+ nextTagCloudId: tagCloudId
7109
+ };
6835
7110
  }
6836
7111
 
6837
7112
  // packages/parser/src/parser/rules/block/module/resolution/styles.ts
@@ -6870,15 +7145,19 @@ async function resolveModules(ast, dataProvider, options) {
6870
7145
  const parse = createModuleParseFunction(options, dataProvider);
6871
7146
  const listPagesCtx = await buildListPagesContext(dataProvider, options.requirements.listPages ?? [], options.compiledListPagesTemplates, parse, options.urlPath);
6872
7147
  const listUsersCtx = await buildListUsersContext(dataProvider, options.requirements.listUsers ?? [], options.compiledListUsersTemplates, parse);
7148
+ const tagCloudCtx = await buildTagCloudContext(dataProvider, options.requirements.tagCloud ?? []);
6873
7149
  const pageTags = dataProvider.getPageTags?.() ?? null;
6874
7150
  const resolvedElements = walkAndResolve(ast.elements, {
6875
7151
  listPages: listPagesCtx,
6876
7152
  listUsers: listUsersCtx,
7153
+ tagCloud: tagCloudCtx,
6877
7154
  fetchListPagesProvided: dataProvider.fetchListPages !== undefined,
6878
7155
  fetchListUsersProvided: dataProvider.fetchListUsers !== undefined,
7156
+ fetchTagCloudProvided: dataProvider.fetchTagCloud !== undefined,
6879
7157
  pageTags,
6880
7158
  listPagesIdCounter: 0,
6881
- listUsersIdCounter: 0
7159
+ listUsersIdCounter: 0,
7160
+ tagCloudIdCounter: 0
6882
7161
  });
6883
7162
  const { elements: finalElements, styles } = collectStyles(resolvedElements.elements);
6884
7163
  const result = {
@@ -13022,6 +13301,7 @@ function parse(source, options) {
13022
13301
  export {
13023
13302
  tokenize,
13024
13303
  text,
13304
+ resolveTagCloud,
13025
13305
  resolveModules,
13026
13306
  resolveListUsers,
13027
13307
  resolveIncludesWithTrace,
@@ -13043,6 +13323,7 @@ export {
13043
13323
  link,
13044
13324
  lineBreak,
13045
13325
  italics,
13326
+ isTagCloudModule,
13046
13327
  isListUsersModule2 as isListUsersModule,
13047
13328
  horizontalRule,
13048
13329
  heading,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdprlib/parser",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "Parser for Wikidot markup",
5
5
  "keywords": [
6
6
  "ast",
@@ -41,6 +41,6 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@braintree/sanitize-url": "^7.1.1",
44
- "@wdprlib/ast": "2.1.0"
44
+ "@wdprlib/ast": "2.2.0"
45
45
  }
46
46
  }
package/src/index.ts CHANGED
@@ -133,6 +133,12 @@ export type {
133
133
  ListUsersDataFetcher,
134
134
  ListUsersVariableContext,
135
135
  ListUsersCompiledTemplate,
136
+ // TagCloud types
137
+ TagCloudDataRequirement,
138
+ TagCloudTagData,
139
+ TagCloudExternalData,
140
+ TagCloudDataFetcher,
141
+ TagCloudModuleData,
136
142
  // Normalized query types
137
143
  NormalizedListPagesQuery,
138
144
  NormalizedTags,
@@ -167,4 +173,7 @@ export {
167
173
  compileListUsersTemplate,
168
174
  isListUsersModule,
169
175
  resolveListUsers,
176
+ // TagCloud
177
+ isTagCloudModule,
178
+ resolveTagCloud,
170
179
  } from "./parser/rules/block/module/index";
@@ -128,6 +128,16 @@ export {
128
128
  resolveListUsers,
129
129
  } from "./listusers";
130
130
 
131
+ // TagCloud module
132
+ export type {
133
+ TagCloudDataRequirement,
134
+ TagCloudTagData,
135
+ TagCloudExternalData,
136
+ TagCloudDataFetcher,
137
+ TagCloudModuleData,
138
+ } from "./tagcloud";
139
+ export { tagCloudModuleRule as tagCloudRule, isTagCloudModule, resolveTagCloud } from "./tagcloud";
140
+
131
141
  // Module resolver
132
142
  export type { ModuleSourceTransform, ResolveOptions } from "./resolve";
133
143
  export { resolveModules } from "./resolve";
@@ -32,6 +32,11 @@ import {
32
32
  isListUsersModule,
33
33
  type ListUsersExtractionState,
34
34
  } from "./extraction/listusers";
35
+ import {
36
+ extractTagCloudModule,
37
+ isTagCloudModule,
38
+ type TagCloudExtractionState,
39
+ } from "./extraction/tagcloud";
35
40
  import type { ExtractionResult } from "./extraction/result";
36
41
  export type { ExtractionResult } from "./extraction/result";
37
42
 
@@ -54,6 +59,7 @@ export function extractDataRequirements(ast: SyntaxTree): ExtractionResult {
54
59
  requirements: {
55
60
  listPages: [],
56
61
  listUsers: [],
62
+ tagCloud: [],
57
63
  },
58
64
  compiledListPagesTemplates: new Map(),
59
65
  compiledListUsersTemplates: new Map(),
@@ -61,6 +67,7 @@ export function extractDataRequirements(ast: SyntaxTree): ExtractionResult {
61
67
 
62
68
  const listPagesState: ListPagesExtractionState = { nextId: 0 };
63
69
  const listUsersState: ListUsersExtractionState = { nextId: 0 };
70
+ const tagCloudState: TagCloudExtractionState = { nextId: 0 };
64
71
 
65
72
  walkElements(ast.elements, (element) => {
66
73
  if (element.element !== "module") return;
@@ -69,6 +76,8 @@ export function extractDataRequirements(ast: SyntaxTree): ExtractionResult {
69
76
  extractListPagesModule(element.data, listPagesState, result);
70
77
  } else if (isListUsersModule(element.data)) {
71
78
  extractListUsersModule(element.data, listUsersState, result);
79
+ } else if (isTagCloudModule(element.data)) {
80
+ extractTagCloudModule(element.data, tagCloudState, result);
72
81
  }
73
82
  });
74
83
 
@@ -0,0 +1,25 @@
1
+ import type { Module } from "@wdprlib/ast";
2
+ import { isTagCloudModule } from "../../tagcloud/resolve";
3
+ import type { ExtractionResult } from "./result";
4
+
5
+ export type TagCloudModuleForExtraction = Extract<Module, { module: "tag-cloud" }>;
6
+
7
+ export interface TagCloudExtractionState {
8
+ nextId: number;
9
+ }
10
+
11
+ export { isTagCloudModule };
12
+
13
+ export function extractTagCloudModule(
14
+ tagCloud: TagCloudModuleForExtraction,
15
+ state: TagCloudExtractionState,
16
+ result: ExtractionResult,
17
+ ): void {
18
+ const id = state.nextId++;
19
+
20
+ result.requirements.tagCloud.push({
21
+ id,
22
+ category: tagCloud.category,
23
+ limit: tagCloud.limit,
24
+ });
25
+ }
@@ -1,4 +1,5 @@
1
1
  import type { ListUsersDataRequirement } from "../../listusers/types";
2
+ import type { TagCloudDataRequirement } from "../../tagcloud/types";
2
3
  import type { ListPagesQuery } from "./query";
3
4
  import type { ListPagesVariable } from "./variables";
4
5
 
@@ -49,4 +50,5 @@ export interface ListPagesDataRequirement {
49
50
  export interface DataRequirements {
50
51
  listPages: ListPagesDataRequirement[];
51
52
  listUsers: ListUsersDataRequirement[];
53
+ tagCloud: TagCloudDataRequirement[];
52
54
  }