@wdprlib/parser 4.1.0 → 4.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.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;
@@ -6692,6 +6893,16 @@ async function buildListUsersDataMap(dataProvider, requirements) {
6692
6893
  }
6693
6894
  return dataMap;
6694
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
+ }
6695
6906
 
6696
6907
  // packages/parser/src/parser/rules/block/module/resolution/contexts.ts
6697
6908
  async function buildListPagesContext(dataProvider, requirements, compiledTemplates, parse, urlPath) {
@@ -6708,6 +6919,16 @@ async function buildListPagesContext(dataProvider, requirements, compiledTemplat
6708
6919
  parse
6709
6920
  };
6710
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
+ }
6711
6932
  async function buildListUsersContext(dataProvider, requirements, compiledTemplates, parse) {
6712
6933
  if (requirements.length === 0 || !dataProvider.fetchListUsers) {
6713
6934
  return null;
@@ -6764,10 +6985,27 @@ function resolveDynamicModuleElement(element, ctx, ids) {
6764
6985
  ids: { ...ids, listUsersId: listUsersId + 1 }
6765
6986
  };
6766
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
+ }
6767
7005
  return { handled: false, elements: [element], ids };
6768
7006
  }
6769
7007
  function countDynamicModules(elements) {
6770
- const counts = { listPagesId: 0, listUsersId: 0 };
7008
+ const counts = { listPagesId: 0, listUsersId: 0, tagCloudId: 0 };
6771
7009
  walkElements(elements, (element) => {
6772
7010
  if (element.element !== "module")
6773
7011
  return;
@@ -6775,6 +7013,8 @@ function countDynamicModules(elements) {
6775
7013
  counts.listPagesId++;
6776
7014
  } else if (isListUsersModule2(element.data)) {
6777
7015
  counts.listUsersId++;
7016
+ } else if (isTagCloudModule(element.data)) {
7017
+ counts.tagCloudId++;
6778
7018
  }
6779
7019
  });
6780
7020
  return counts;
@@ -6785,12 +7025,18 @@ function walkAndResolve(elements, ctx) {
6785
7025
  const result = [];
6786
7026
  let listPagesId = ctx.listPagesIdCounter;
6787
7027
  let listUsersId = ctx.listUsersIdCounter;
7028
+ let tagCloudId = ctx.tagCloudIdCounter;
6788
7029
  for (const element of elements) {
6789
- const dynamicModule = resolveDynamicModuleElement(element, ctx, { listPagesId, listUsersId });
7030
+ const dynamicModule = resolveDynamicModuleElement(element, ctx, {
7031
+ listPagesId,
7032
+ listUsersId,
7033
+ tagCloudId
7034
+ });
6790
7035
  if (dynamicModule.handled) {
6791
7036
  result.push(...dynamicModule.elements);
6792
7037
  listPagesId = dynamicModule.ids.listPagesId;
6793
7038
  listUsersId = dynamicModule.ids.listUsersId;
7039
+ tagCloudId = dynamicModule.ids.tagCloudId;
6794
7040
  continue;
6795
7041
  }
6796
7042
  if (isIfTagsElement(element)) {
@@ -6801,21 +7047,25 @@ function walkAndResolve(elements, ctx) {
6801
7047
  const childResult = walkAndResolve(ifTagsData.elements, {
6802
7048
  ...ctx,
6803
7049
  listPagesIdCounter: listPagesId,
6804
- listUsersIdCounter: listUsersId
7050
+ listUsersIdCounter: listUsersId,
7051
+ tagCloudIdCounter: tagCloudId
6805
7052
  });
6806
7053
  result.push(...childResult.elements);
6807
7054
  listPagesId = childResult.nextListPagesId;
6808
7055
  listUsersId = childResult.nextListUsersId;
7056
+ tagCloudId = childResult.nextTagCloudId;
6809
7057
  } else {
6810
7058
  const counts = countDynamicModules(ifTagsData.elements);
6811
7059
  listPagesId += counts.listPagesId;
6812
7060
  listUsersId += counts.listUsersId;
7061
+ tagCloudId += counts.tagCloudId;
6813
7062
  }
6814
7063
  } else {
6815
7064
  const childResult = walkAndResolve(ifTagsData.elements, {
6816
7065
  ...ctx,
6817
7066
  listPagesIdCounter: listPagesId,
6818
- listUsersIdCounter: listUsersId
7067
+ listUsersIdCounter: listUsersId,
7068
+ tagCloudIdCounter: tagCloudId
6819
7069
  });
6820
7070
  result.push({
6821
7071
  element: "if-tags",
@@ -6826,28 +7076,37 @@ function walkAndResolve(elements, ctx) {
6826
7076
  });
6827
7077
  listPagesId = childResult.nextListPagesId;
6828
7078
  listUsersId = childResult.nextListUsersId;
7079
+ tagCloudId = childResult.nextTagCloudId;
6829
7080
  }
6830
7081
  continue;
6831
7082
  }
6832
- const mapped = mapElementChildrenWithState(element, { listPagesId, listUsersId }, (children, state) => {
7083
+ const mapped = mapElementChildrenWithState(element, { listPagesId, listUsersId, tagCloudId }, (children, state) => {
6833
7084
  const childResult = walkAndResolve(children, {
6834
7085
  ...ctx,
6835
7086
  listPagesIdCounter: state.listPagesId,
6836
- listUsersIdCounter: state.listUsersId
7087
+ listUsersIdCounter: state.listUsersId,
7088
+ tagCloudIdCounter: state.tagCloudId
6837
7089
  });
6838
7090
  return {
6839
7091
  elements: childResult.elements,
6840
7092
  state: {
6841
7093
  listPagesId: childResult.nextListPagesId,
6842
- listUsersId: childResult.nextListUsersId
7094
+ listUsersId: childResult.nextListUsersId,
7095
+ tagCloudId: childResult.nextTagCloudId
6843
7096
  }
6844
7097
  };
6845
7098
  });
6846
7099
  result.push(mapped.element);
6847
7100
  listPagesId = mapped.state.listPagesId;
6848
7101
  listUsersId = mapped.state.listUsersId;
7102
+ tagCloudId = mapped.state.tagCloudId;
6849
7103
  }
6850
- return { elements: result, nextListPagesId: listPagesId, nextListUsersId: listUsersId };
7104
+ return {
7105
+ elements: result,
7106
+ nextListPagesId: listPagesId,
7107
+ nextListUsersId: listUsersId,
7108
+ nextTagCloudId: tagCloudId
7109
+ };
6851
7110
  }
6852
7111
 
6853
7112
  // packages/parser/src/parser/rules/block/module/resolution/styles.ts
@@ -6886,15 +7145,19 @@ async function resolveModules(ast, dataProvider, options) {
6886
7145
  const parse = createModuleParseFunction(options, dataProvider);
6887
7146
  const listPagesCtx = await buildListPagesContext(dataProvider, options.requirements.listPages ?? [], options.compiledListPagesTemplates, parse, options.urlPath);
6888
7147
  const listUsersCtx = await buildListUsersContext(dataProvider, options.requirements.listUsers ?? [], options.compiledListUsersTemplates, parse);
7148
+ const tagCloudCtx = await buildTagCloudContext(dataProvider, options.requirements.tagCloud ?? []);
6889
7149
  const pageTags = dataProvider.getPageTags?.() ?? null;
6890
7150
  const resolvedElements = walkAndResolve(ast.elements, {
6891
7151
  listPages: listPagesCtx,
6892
7152
  listUsers: listUsersCtx,
7153
+ tagCloud: tagCloudCtx,
6893
7154
  fetchListPagesProvided: dataProvider.fetchListPages !== undefined,
6894
7155
  fetchListUsersProvided: dataProvider.fetchListUsers !== undefined,
7156
+ fetchTagCloudProvided: dataProvider.fetchTagCloud !== undefined,
6895
7157
  pageTags,
6896
7158
  listPagesIdCounter: 0,
6897
- listUsersIdCounter: 0
7159
+ listUsersIdCounter: 0,
7160
+ tagCloudIdCounter: 0
6898
7161
  });
6899
7162
  const { elements: finalElements, styles } = collectStyles(resolvedElements.elements);
6900
7163
  const result = {
@@ -8994,6 +9257,177 @@ var bibliographyRule = {
8994
9257
  }
8995
9258
  };
8996
9259
 
9260
+ // packages/parser/src/parser/rules/block/gallery/items.ts
9261
+ function parseGalleryItemLine(content) {
9262
+ const spacePos = content.indexOf(" ");
9263
+ let source = spacePos < 0 ? content : content.slice(0, spacePos);
9264
+ const attrText = spacePos < 0 ? "" : content.slice(spacePos + 1);
9265
+ let newWindow = false;
9266
+ if (source.startsWith("*")) {
9267
+ source = source.slice(1);
9268
+ newWindow = true;
9269
+ }
9270
+ const attrs = parseItemAttrs(attrText);
9271
+ let link = attrs.get("link") ?? null;
9272
+ if (link !== null && link.startsWith("*")) {
9273
+ newWindow = true;
9274
+ link = link.slice(1);
9275
+ }
9276
+ const alt = attrs.get("alt") ?? null;
9277
+ return { source, link, alt, newWindow };
9278
+ }
9279
+ function parseItemAttrs(text) {
9280
+ const attrs = new Map;
9281
+ const parts = text.trim().split('="');
9282
+ let key = parts[0]?.trim() ?? "";
9283
+ for (let i = 1;i < parts.length; i++) {
9284
+ const val = parts[i] ?? "";
9285
+ const quotePos = val.lastIndexOf('"');
9286
+ if (quotePos < 0) {
9287
+ attrs.set(key, "");
9288
+ key = val.slice(1).trim();
9289
+ } else {
9290
+ attrs.set(key, stripslashes(val.slice(0, quotePos)));
9291
+ key = val.slice(quotePos + 1).trim();
9292
+ }
9293
+ }
9294
+ return attrs;
9295
+ }
9296
+ function stripslashes(value) {
9297
+ return value.replace(/\\(.)/gs, "$1").replace(/\\$/, "");
9298
+ }
9299
+
9300
+ // packages/parser/src/parser/rules/block/gallery/index.ts
9301
+ var GALLERY_SIZES = ["small", "medium", "thumbnail", "square", "original"];
9302
+ function normalizeSize(value) {
9303
+ return value !== undefined && GALLERY_SIZES.includes(value) ? value : "thumbnail";
9304
+ }
9305
+ function normalizeViewer(value) {
9306
+ return value !== "no" && value !== "false";
9307
+ }
9308
+ function normalizeOrder(value) {
9309
+ switch (value) {
9310
+ case "name":
9311
+ case "name desc":
9312
+ case "created_at":
9313
+ case "created_at desc":
9314
+ return value;
9315
+ case "nameDesc":
9316
+ return "name desc";
9317
+ case "dateAdded":
9318
+ return "created_at";
9319
+ case "dateAddedDesc":
9320
+ return "created_at desc";
9321
+ case "name desc desc":
9322
+ return "name";
9323
+ case "created_at desc desc":
9324
+ return "created_at";
9325
+ default:
9326
+ return "name";
9327
+ }
9328
+ }
9329
+ function tryParseGalleryContent(ctx, pos) {
9330
+ const start = pos;
9331
+ if (ctx.tokens[pos]?.type !== "NEWLINE") {
9332
+ return null;
9333
+ }
9334
+ const lines = [];
9335
+ let p = pos + 1;
9336
+ for (;; ) {
9337
+ const colon = ctx.tokens[p];
9338
+ if (colon?.type !== "COLON" || !colon.lineStart) {
9339
+ break;
9340
+ }
9341
+ const space = ctx.tokens[p + 1];
9342
+ if (space?.type !== "WHITESPACE" || !space.value.startsWith(" ")) {
9343
+ break;
9344
+ }
9345
+ let content = "";
9346
+ let q = p + 1;
9347
+ while (q < ctx.tokens.length) {
9348
+ const token5 = ctx.tokens[q];
9349
+ if (!token5 || token5.type === "NEWLINE" || token5.type === "EOF") {
9350
+ break;
9351
+ }
9352
+ content += token5.value;
9353
+ q++;
9354
+ }
9355
+ if (content === " ") {
9356
+ return null;
9357
+ }
9358
+ if (ctx.tokens[q]?.type !== "NEWLINE") {
9359
+ return null;
9360
+ }
9361
+ lines.push(content.trim());
9362
+ p = q + 1;
9363
+ }
9364
+ if (lines.length === 0) {
9365
+ return null;
9366
+ }
9367
+ if (ctx.tokens[p]?.type !== "BLOCK_END_OPEN") {
9368
+ return null;
9369
+ }
9370
+ const nameResult = parseBlockName(ctx, p + 1);
9371
+ if (!nameResult || nameResult.name !== "gallery") {
9372
+ return null;
9373
+ }
9374
+ const closePos = p + 1 + nameResult.consumed;
9375
+ if (ctx.tokens[closePos]?.type !== "BLOCK_CLOSE") {
9376
+ return null;
9377
+ }
9378
+ return { lines, consumed: closePos + 1 - start };
9379
+ }
9380
+ var galleryRule = {
9381
+ name: "gallery",
9382
+ startTokens: ["BLOCK_OPEN"],
9383
+ requiresLineStart: true,
9384
+ parse(ctx) {
9385
+ if (ctx.tokens[ctx.pos]?.type !== "BLOCK_OPEN") {
9386
+ return { success: false };
9387
+ }
9388
+ let pos = ctx.pos + 1;
9389
+ const nameResult = parseBlockName(ctx, pos);
9390
+ if (!nameResult || nameResult.name !== "gallery") {
9391
+ return { success: false };
9392
+ }
9393
+ pos += nameResult.consumed;
9394
+ const attrResult = parseAttributesRaw(ctx, pos);
9395
+ pos += attrResult.consumed;
9396
+ if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
9397
+ return { success: false };
9398
+ }
9399
+ pos++;
9400
+ const size = normalizeSize(attrResult.attrs.size);
9401
+ const viewer = normalizeViewer(attrResult.attrs.viewer);
9402
+ const order = normalizeOrder(attrResult.attrs.order);
9403
+ const openConsumed = pos - ctx.pos;
9404
+ const content = tryParseGalleryContent(ctx, pos);
9405
+ if (!content) {
9406
+ return {
9407
+ success: true,
9408
+ elements: [
9409
+ {
9410
+ element: "gallery",
9411
+ data: { size, order, viewer, content: { type: "auto", files: null } }
9412
+ }
9413
+ ],
9414
+ consumed: openConsumed
9415
+ };
9416
+ }
9417
+ const items = content.lines.map(parseGalleryItemLine);
9418
+ return {
9419
+ success: true,
9420
+ elements: [
9421
+ {
9422
+ element: "gallery",
9423
+ data: { size, order, viewer, content: { type: "items", items } }
9424
+ }
9425
+ ],
9426
+ consumed: openConsumed + content.consumed
9427
+ };
9428
+ }
9429
+ };
9430
+
8997
9431
  // packages/parser/src/parser/rules/block/index.ts
8998
9432
  var blockRules = [
8999
9433
  blockCommentRule,
@@ -9023,6 +9457,7 @@ var blockRules = [
9023
9457
  iframeRule,
9024
9458
  iftagsRule,
9025
9459
  bibliographyRule,
9460
+ galleryRule,
9026
9461
  divRule
9027
9462
  ];
9028
9463
  // packages/parser/src/parser/rules/inline/formatting/container.ts
@@ -13038,6 +13473,7 @@ function parse(source, options) {
13038
13473
  export {
13039
13474
  tokenize,
13040
13475
  text,
13476
+ resolveTagCloud,
13041
13477
  resolveModules,
13042
13478
  resolveListUsers,
13043
13479
  resolveIncludesWithTrace,
@@ -13059,6 +13495,7 @@ export {
13059
13495
  link,
13060
13496
  lineBreak,
13061
13497
  italics,
13498
+ isTagCloudModule,
13062
13499
  isListUsersModule2 as isListUsersModule,
13063
13500
  horizontalRule,
13064
13501
  heading,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdprlib/parser",
3
- "version": "4.1.0",
3
+ "version": "4.3.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.3.0"
45
45
  }
46
46
  }
package/src/index.ts CHANGED
@@ -58,6 +58,12 @@ export type {
58
58
  DateItem,
59
59
  Embed,
60
60
  TocEntry,
61
+ // Gallery
62
+ GallerySize,
63
+ GalleryOrder,
64
+ GalleryItem,
65
+ GalleryContent,
66
+ GalleryData,
61
67
  // Diagnostics
62
68
  Diagnostic,
63
69
  DiagnosticSeverity,
@@ -133,6 +139,12 @@ export type {
133
139
  ListUsersDataFetcher,
134
140
  ListUsersVariableContext,
135
141
  ListUsersCompiledTemplate,
142
+ // TagCloud types
143
+ TagCloudDataRequirement,
144
+ TagCloudTagData,
145
+ TagCloudExternalData,
146
+ TagCloudDataFetcher,
147
+ TagCloudModuleData,
136
148
  // Normalized query types
137
149
  NormalizedListPagesQuery,
138
150
  NormalizedTags,
@@ -167,4 +179,7 @@ export {
167
179
  compileListUsersTemplate,
168
180
  isListUsersModule,
169
181
  resolveListUsers,
182
+ // TagCloud
183
+ isTagCloudModule,
184
+ resolveTagCloud,
170
185
  } from "./parser/rules/block/module/index";