@wdprlib/parser 4.0.0 → 4.1.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
@@ -5709,11 +5709,32 @@ function resolveListPages(module2, data, compiledTemplate, parse) {
5709
5709
  const items = renderListPagesItems(module2, data, compiledTemplate, parse);
5710
5710
  return wrapListPagesResult(module2, items, parse);
5711
5711
  }
5712
+ // packages/parser/src/parser/rules/block/module/listpages/url-resolution/fields.ts
5713
+ var URL_RESOLVABLE_FIELDS = [
5714
+ { attr: "offset", queryKey: "offset", type: "number" },
5715
+ { attr: "limit", queryKey: "limit", type: "number" },
5716
+ { attr: "per-page", queryKey: "perPage", type: "number" },
5717
+ { attr: "order", queryKey: "order", type: "string" },
5718
+ { attr: "tags", queryKey: "tags", type: "string", urlAttrs: ["tag"] },
5719
+ { attr: "category", queryKey: "category", type: "string" },
5720
+ { attr: "parent", queryKey: "parent", type: "string" },
5721
+ { attr: "range", queryKey: "range", type: "string" },
5722
+ { attr: "name", queryKey: "name", type: "string" },
5723
+ { attr: "fullname", queryKey: "fullname", type: "string" },
5724
+ { attr: "created-at", queryKey: "createdAt", type: "string" },
5725
+ { attr: "updated-at", queryKey: "updatedAt", type: "string" },
5726
+ { attr: "created-by", queryKey: "createdBy", type: "string" },
5727
+ { attr: "rating", queryKey: "rating", type: "string" },
5728
+ { attr: "votes", queryKey: "votes", type: "string" },
5729
+ { attr: "reverse", queryKey: "reverse", type: "boolean" }
5730
+ ];
5731
+
5712
5732
  // packages/parser/src/parser/rules/block/module/listpages/url-resolution/params.ts
5713
5733
  function parseUrlParams(url) {
5714
5734
  const params = new Map;
5715
5735
  const parts = url.split("/").filter(Boolean);
5716
- for (let i = 1;i < parts.length - 1; i += 2) {
5736
+ const pairStart = isUrlParameter(parts[0]) ? 0 : 1;
5737
+ for (let i = pairStart;i < parts.length - 1; i += 2) {
5717
5738
  const key = parts[i];
5718
5739
  const value = parts[i + 1];
5719
5740
  if (key && value) {
@@ -5722,6 +5743,10 @@ function parseUrlParams(url) {
5722
5743
  }
5723
5744
  return params;
5724
5745
  }
5746
+ var URL_PARAMETER_NAMES = new Set(URL_RESOLVABLE_FIELDS.flatMap((field) => [field.attr, ...field.urlAttrs ?? []]));
5747
+ function isUrlParameter(param) {
5748
+ return param !== undefined && URL_PARAMETER_NAMES.has(param);
5749
+ }
5725
5750
  // packages/parser/src/parser/rules/block/module/listpages/normalization/tags-category.ts
5726
5751
  var TOKEN_SEPARATOR = /[,;\s]+/;
5727
5752
  function parseTags(value) {
@@ -5977,26 +6002,6 @@ function normalizeQuery(query) {
5977
6002
  return result;
5978
6003
  }
5979
6004
 
5980
- // packages/parser/src/parser/rules/block/module/listpages/url-resolution/fields.ts
5981
- var URL_RESOLVABLE_FIELDS = [
5982
- { attr: "offset", queryKey: "offset", type: "number" },
5983
- { attr: "limit", queryKey: "limit", type: "number" },
5984
- { attr: "per-page", queryKey: "perPage", type: "number" },
5985
- { attr: "order", queryKey: "order", type: "string" },
5986
- { attr: "tags", queryKey: "tags", type: "string" },
5987
- { attr: "category", queryKey: "category", type: "string" },
5988
- { attr: "parent", queryKey: "parent", type: "string" },
5989
- { attr: "range", queryKey: "range", type: "string" },
5990
- { attr: "name", queryKey: "name", type: "string" },
5991
- { attr: "fullname", queryKey: "fullname", type: "string" },
5992
- { attr: "created-at", queryKey: "createdAt", type: "string" },
5993
- { attr: "updated-at", queryKey: "updatedAt", type: "string" },
5994
- { attr: "created-by", queryKey: "createdBy", type: "string" },
5995
- { attr: "rating", queryKey: "rating", type: "string" },
5996
- { attr: "votes", queryKey: "votes", type: "string" },
5997
- { attr: "reverse", queryKey: "reverse", type: "boolean" }
5998
- ];
5999
-
6000
6005
  // packages/parser/src/parser/rules/block/module/listpages/url-resolution/query.ts
6001
6006
  function assignResolvedUrlField(query, field, value) {
6002
6007
  switch (field.type) {
@@ -6017,15 +6022,23 @@ function assignResolvedUrlField(query, field, value) {
6017
6022
  }
6018
6023
 
6019
6024
  // packages/parser/src/parser/rules/block/module/listpages/url-resolution/value.ts
6020
- function resolveUrlValue(rawValue, paramName, urlParams, prefix) {
6025
+ function resolveUrlValue(rawValue, paramNames, urlParams, prefix) {
6021
6026
  if (!rawValue)
6022
6027
  return;
6023
6028
  if (!rawValue.startsWith("@URL")) {
6024
6029
  return rawValue;
6025
6030
  }
6026
6031
  const defaultValue = rawValue.includes("|") ? rawValue.split("|")[1] : undefined;
6027
- const actualParamName = prefix ? `${prefix}_${paramName}` : paramName;
6028
- return urlParams.get(actualParamName) ?? defaultValue;
6032
+ for (const paramName of toParamNames(paramNames)) {
6033
+ const actualParamName = prefix ? `${prefix}_${paramName}` : paramName;
6034
+ const value = urlParams.get(actualParamName);
6035
+ if (value !== undefined)
6036
+ return value;
6037
+ }
6038
+ return defaultValue;
6039
+ }
6040
+ function toParamNames(paramNames) {
6041
+ return typeof paramNames === "string" ? [paramNames] : paramNames;
6029
6042
  }
6030
6043
 
6031
6044
  // packages/parser/src/parser/rules/block/module/listpages/url-resolution/resolve.ts
@@ -6036,13 +6049,16 @@ function resolveQuery(requirement, urlParams) {
6036
6049
  const rawValue = rawAttributes[field.attr];
6037
6050
  if (!rawValue)
6038
6051
  continue;
6039
- const resolvedValue = resolveUrlValue(rawValue, field.attr, urlParams, urlAttrPrefix);
6052
+ const resolvedValue = resolveUrlValue(rawValue, getUrlParamNames(field), urlParams, urlAttrPrefix);
6040
6053
  if (resolvedValue === undefined)
6041
6054
  continue;
6042
6055
  assignResolvedUrlField(resolved, field, resolvedValue);
6043
6056
  }
6044
6057
  return resolved;
6045
6058
  }
6059
+ function getUrlParamNames(field) {
6060
+ return field.urlAttrs ? [field.attr, ...field.urlAttrs] : [field.attr];
6061
+ }
6046
6062
  function resolveAndNormalizeQuery(requirement, urlParams) {
6047
6063
  const resolved = resolveQuery(requirement, urlParams);
6048
6064
  return normalizeQuery(resolved);
package/dist/index.js CHANGED
@@ -5650,11 +5650,32 @@ function resolveListPages(module, data, compiledTemplate, parse) {
5650
5650
  const items = renderListPagesItems(module, data, compiledTemplate, parse);
5651
5651
  return wrapListPagesResult(module, items, parse);
5652
5652
  }
5653
+ // packages/parser/src/parser/rules/block/module/listpages/url-resolution/fields.ts
5654
+ var URL_RESOLVABLE_FIELDS = [
5655
+ { attr: "offset", queryKey: "offset", type: "number" },
5656
+ { attr: "limit", queryKey: "limit", type: "number" },
5657
+ { attr: "per-page", queryKey: "perPage", type: "number" },
5658
+ { attr: "order", queryKey: "order", type: "string" },
5659
+ { attr: "tags", queryKey: "tags", type: "string", urlAttrs: ["tag"] },
5660
+ { attr: "category", queryKey: "category", type: "string" },
5661
+ { attr: "parent", queryKey: "parent", type: "string" },
5662
+ { attr: "range", queryKey: "range", type: "string" },
5663
+ { attr: "name", queryKey: "name", type: "string" },
5664
+ { attr: "fullname", queryKey: "fullname", type: "string" },
5665
+ { attr: "created-at", queryKey: "createdAt", type: "string" },
5666
+ { attr: "updated-at", queryKey: "updatedAt", type: "string" },
5667
+ { attr: "created-by", queryKey: "createdBy", type: "string" },
5668
+ { attr: "rating", queryKey: "rating", type: "string" },
5669
+ { attr: "votes", queryKey: "votes", type: "string" },
5670
+ { attr: "reverse", queryKey: "reverse", type: "boolean" }
5671
+ ];
5672
+
5653
5673
  // packages/parser/src/parser/rules/block/module/listpages/url-resolution/params.ts
5654
5674
  function parseUrlParams(url) {
5655
5675
  const params = new Map;
5656
5676
  const parts = url.split("/").filter(Boolean);
5657
- for (let i = 1;i < parts.length - 1; i += 2) {
5677
+ const pairStart = isUrlParameter(parts[0]) ? 0 : 1;
5678
+ for (let i = pairStart;i < parts.length - 1; i += 2) {
5658
5679
  const key = parts[i];
5659
5680
  const value = parts[i + 1];
5660
5681
  if (key && value) {
@@ -5663,6 +5684,10 @@ function parseUrlParams(url) {
5663
5684
  }
5664
5685
  return params;
5665
5686
  }
5687
+ var URL_PARAMETER_NAMES = new Set(URL_RESOLVABLE_FIELDS.flatMap((field) => [field.attr, ...field.urlAttrs ?? []]));
5688
+ function isUrlParameter(param) {
5689
+ return param !== undefined && URL_PARAMETER_NAMES.has(param);
5690
+ }
5666
5691
  // packages/parser/src/parser/rules/block/module/listpages/normalization/tags-category.ts
5667
5692
  var TOKEN_SEPARATOR = /[,;\s]+/;
5668
5693
  function parseTags(value) {
@@ -5918,26 +5943,6 @@ function normalizeQuery(query) {
5918
5943
  return result;
5919
5944
  }
5920
5945
 
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
5946
  // packages/parser/src/parser/rules/block/module/listpages/url-resolution/query.ts
5942
5947
  function assignResolvedUrlField(query, field, value) {
5943
5948
  switch (field.type) {
@@ -5958,15 +5963,23 @@ function assignResolvedUrlField(query, field, value) {
5958
5963
  }
5959
5964
 
5960
5965
  // packages/parser/src/parser/rules/block/module/listpages/url-resolution/value.ts
5961
- function resolveUrlValue(rawValue, paramName, urlParams, prefix) {
5966
+ function resolveUrlValue(rawValue, paramNames, urlParams, prefix) {
5962
5967
  if (!rawValue)
5963
5968
  return;
5964
5969
  if (!rawValue.startsWith("@URL")) {
5965
5970
  return rawValue;
5966
5971
  }
5967
5972
  const defaultValue = rawValue.includes("|") ? rawValue.split("|")[1] : undefined;
5968
- const actualParamName = prefix ? `${prefix}_${paramName}` : paramName;
5969
- return urlParams.get(actualParamName) ?? defaultValue;
5973
+ for (const paramName of toParamNames(paramNames)) {
5974
+ const actualParamName = prefix ? `${prefix}_${paramName}` : paramName;
5975
+ const value = urlParams.get(actualParamName);
5976
+ if (value !== undefined)
5977
+ return value;
5978
+ }
5979
+ return defaultValue;
5980
+ }
5981
+ function toParamNames(paramNames) {
5982
+ return typeof paramNames === "string" ? [paramNames] : paramNames;
5970
5983
  }
5971
5984
 
5972
5985
  // packages/parser/src/parser/rules/block/module/listpages/url-resolution/resolve.ts
@@ -5977,13 +5990,16 @@ function resolveQuery(requirement, urlParams) {
5977
5990
  const rawValue = rawAttributes[field.attr];
5978
5991
  if (!rawValue)
5979
5992
  continue;
5980
- const resolvedValue = resolveUrlValue(rawValue, field.attr, urlParams, urlAttrPrefix);
5993
+ const resolvedValue = resolveUrlValue(rawValue, getUrlParamNames(field), urlParams, urlAttrPrefix);
5981
5994
  if (resolvedValue === undefined)
5982
5995
  continue;
5983
5996
  assignResolvedUrlField(resolved, field, resolvedValue);
5984
5997
  }
5985
5998
  return resolved;
5986
5999
  }
6000
+ function getUrlParamNames(field) {
6001
+ return field.urlAttrs ? [field.attr, ...field.urlAttrs] : [field.attr];
6002
+ }
5987
6003
  function resolveAndNormalizeQuery(requirement, urlParams) {
5988
6004
  const resolved = resolveQuery(requirement, urlParams);
5989
6005
  return normalizeQuery(resolved);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdprlib/parser",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "Parser for Wikidot markup",
5
5
  "keywords": [
6
6
  "ast",
@@ -1,9 +1,9 @@
1
1
  import type { ListPagesQuery } from "../types";
2
2
 
3
3
  export type UrlResolvableField =
4
- | { attr: string; queryKey: StringUrlQueryKey; type: "string" }
5
- | { attr: string; queryKey: NumberUrlQueryKey; type: "number" }
6
- | { attr: string; queryKey: BooleanUrlQueryKey; type: "boolean" };
4
+ | { attr: string; queryKey: StringUrlQueryKey; type: "string"; urlAttrs?: readonly string[] }
5
+ | { attr: string; queryKey: NumberUrlQueryKey; type: "number"; urlAttrs?: readonly string[] }
6
+ | { attr: string; queryKey: BooleanUrlQueryKey; type: "boolean"; urlAttrs?: readonly string[] };
7
7
 
8
8
  type StringUrlQueryKey = Extract<
9
9
  keyof ListPagesQuery,
@@ -33,7 +33,7 @@ export const URL_RESOLVABLE_FIELDS: readonly UrlResolvableField[] = [
33
33
  { attr: "limit", queryKey: "limit", type: "number" },
34
34
  { attr: "per-page", queryKey: "perPage", type: "number" },
35
35
  { attr: "order", queryKey: "order", type: "string" },
36
- { attr: "tags", queryKey: "tags", type: "string" },
36
+ { attr: "tags", queryKey: "tags", type: "string", urlAttrs: ["tag"] },
37
37
  { attr: "category", queryKey: "category", type: "string" },
38
38
  { attr: "parent", queryKey: "parent", type: "string" },
39
39
  { attr: "range", queryKey: "range", type: "string" },
@@ -1,3 +1,5 @@
1
+ import { URL_RESOLVABLE_FIELDS } from "./fields";
2
+
1
3
  /**
2
4
  * Parse URL path parameters like /offset/1/page2_limit/1.
3
5
  * Returns a map of parameter name -> value.
@@ -5,9 +7,10 @@
5
7
  export function parseUrlParams(url: string): Map<string, string> {
6
8
  const params = new Map<string, string>();
7
9
  const parts = url.split("/").filter(Boolean);
10
+ const pairStart = isUrlParameter(parts[0]) ? 0 : 1;
8
11
 
9
12
  // Skip the page name (first part), parse key/value pairs.
10
- for (let i = 1; i < parts.length - 1; i += 2) {
13
+ for (let i = pairStart; i < parts.length - 1; i += 2) {
11
14
  const key = parts[i];
12
15
  const value = parts[i + 1];
13
16
  if (key && value) {
@@ -17,3 +20,11 @@ export function parseUrlParams(url: string): Map<string, string> {
17
20
 
18
21
  return params;
19
22
  }
23
+
24
+ const URL_PARAMETER_NAMES = new Set(
25
+ URL_RESOLVABLE_FIELDS.flatMap((field) => [field.attr, ...(field.urlAttrs ?? [])]),
26
+ );
27
+
28
+ function isUrlParameter(param: string | undefined): boolean {
29
+ return param !== undefined && URL_PARAMETER_NAMES.has(param);
30
+ }
@@ -25,7 +25,12 @@ export function resolveQuery(
25
25
  const rawValue = rawAttributes[field.attr];
26
26
  if (!rawValue) continue;
27
27
 
28
- const resolvedValue = resolveUrlValue(rawValue, field.attr, urlParams, urlAttrPrefix);
28
+ const resolvedValue = resolveUrlValue(
29
+ rawValue,
30
+ getUrlParamNames(field),
31
+ urlParams,
32
+ urlAttrPrefix,
33
+ );
29
34
  if (resolvedValue === undefined) continue;
30
35
 
31
36
  assignResolvedUrlField(resolved, field, resolvedValue);
@@ -34,6 +39,10 @@ export function resolveQuery(
34
39
  return resolved;
35
40
  }
36
41
 
42
+ function getUrlParamNames(field: (typeof URL_RESOLVABLE_FIELDS)[number]): readonly string[] {
43
+ return field.urlAttrs ? [field.attr, ...field.urlAttrs] : [field.attr];
44
+ }
45
+
37
46
  /**
38
47
  * Resolve all `@URL` parameters and normalize the query.
39
48
  *
@@ -2,14 +2,14 @@
2
2
  * Resolve @URL|default format with actual URL parameters.
3
3
  *
4
4
  * @param rawValue - The raw attribute value (e.g., "@URL|0")
5
- * @param paramName - The parameter name (e.g., "offset")
5
+ * @param paramNames - The parameter name or names (e.g., "offset")
6
6
  * @param urlParams - Parsed URL parameters
7
7
  * @param prefix - Optional URL attribute prefix (e.g., "page2")
8
8
  * @returns Resolved value
9
9
  */
10
10
  export function resolveUrlValue(
11
11
  rawValue: string | undefined,
12
- paramName: string,
12
+ paramNames: string | readonly string[],
13
13
  urlParams: Map<string, string>,
14
14
  prefix?: string,
15
15
  ): string | undefined {
@@ -20,6 +20,15 @@ export function resolveUrlValue(
20
20
  }
21
21
 
22
22
  const defaultValue = rawValue.includes("|") ? rawValue.split("|")[1] : undefined;
23
- const actualParamName = prefix ? `${prefix}_${paramName}` : paramName;
24
- return urlParams.get(actualParamName) ?? defaultValue;
23
+ for (const paramName of toParamNames(paramNames)) {
24
+ const actualParamName = prefix ? `${prefix}_${paramName}` : paramName;
25
+ const value = urlParams.get(actualParamName);
26
+ if (value !== undefined) return value;
27
+ }
28
+
29
+ return defaultValue;
30
+ }
31
+
32
+ function toParamNames(paramNames: string | readonly string[]): readonly string[] {
33
+ return typeof paramNames === "string" ? [paramNames] : paramNames;
25
34
  }