anu-verzum 1.4.0 → 1.6.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/README.md CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  <h3>@author: <strong>Anubis-programmer</strong></h3>
6
6
  <h3>@license: <strong>MIT</strong></h3>
7
+ <h3>@version: <strong>1.6.0</strong></h3>
7
8
 
8
9
  <br>
9
10
 
@@ -193,6 +194,9 @@ npm run format # Format all source files with Prettier
193
194
  <li>
194
195
  <a href="#redirecting-with-history-goto">Redirecting with Anu.History.goTo()</a>
195
196
  </li>
197
+ <li>
198
+ <a href="#reading-url-parameters">Reading URL parameters</a>
199
+ </li>
196
200
  </ul>
197
201
  <li>
198
202
  <a href="#server-api">Calling the server asynchronously - The Server API</a>
@@ -1316,6 +1320,37 @@ when you want to imperatively modify a child outside of the typical dataflow.
1316
1320
  Anu.History.goTo('/about', true);
1317
1321
  ```
1318
1322
 
1323
+ <h3 id="reading-url-parameters">Reading URL parameters - <strong><code>Anu.History.getUrlParams()</code> and <code>Anu.History.getAllUrlParamNames()</code></strong></h3>
1324
+
1325
+ URLs are expected to follow the REST resource-path convention:
1326
+
1327
+ ```
1328
+ /{noun-plural}/{id}/{noun-plural}/{id}/...
1329
+ ```
1330
+
1331
+ The router parses the current pathname into named parameters by singularizing each noun segment and appending `Id`.
1332
+ A trailing action segment (odd-length path) is ignored.
1333
+
1334
+ | URL | Extracted params |
1335
+ |---|---|
1336
+ | `/products` | `{}` |
1337
+ | `/products/a3f8c2d1` | `{ productId: 'a3f8c2d1' }` |
1338
+ | `/users/asdf1234/products` | `{ userId: 'asdf1234' }` |
1339
+ | `/users/asdf1234/products/ghjk5678` | `{ userId: 'asdf1234', productId: 'ghjk5678' }` |
1340
+ | `/users/asdf1234/products/ghjk5678/delete` | `{ userId: 'asdf1234', productId: 'ghjk5678' }` |
1341
+
1342
+ - **`Anu.History.getUrlParams(key)`** — returns the value of the named URL parameter derived from the current pathname, or `null` if the key is not present.
1343
+ - **`Anu.History.getAllUrlParamNames()`** — returns an array of all parameter key names extractable from the current pathname. Useful for development and debugging.
1344
+
1345
+ ```typescript
1346
+ // URL: /users/asdf1234/products/ghjk5678
1347
+ Anu.History.getUrlParams('userId'); // → 'asdf1234'
1348
+ Anu.History.getUrlParams('productId'); // → 'ghjk5678'
1349
+ Anu.History.getUrlParams('orderId'); // → null
1350
+
1351
+ Anu.History.getAllUrlParamNames(); // → ['userId', 'productId']
1352
+ ```
1353
+
1319
1354
  <br>
1320
1355
 
1321
1356
  <h2 id="server-api">Calling the server asynchronously - <strong>The Server API</strong></h2>
@@ -17,7 +17,7 @@ class Component {
17
17
  this.state = this.state || {};
18
18
  }
19
19
  setState(partialState = {}) {
20
- let partialStateObject = this.state;
20
+ let partialStateObject = {};
21
21
  let partialStateCallback;
22
22
  if (typeof partialState === 'object') {
23
23
  partialStateObject = {
@@ -44,5 +44,7 @@ declare const History: {
44
44
  Link: typeof HistoryLink;
45
45
  Redirect: typeof HistoryRedirect;
46
46
  Route: typeof HistoryRoute;
47
+ getUrlParams: (key: string) => string | null;
48
+ getAllUrlParamNames: () => string[];
47
49
  };
48
50
  export default History;
@@ -68,6 +68,38 @@ const matchPath = (pathname, options) => {
68
68
  isExact
69
69
  };
70
70
  };
71
+ const singularize = word => {
72
+ if (word.endsWith('ies')) {
73
+ return `${word.slice(0, -3)}y`;
74
+ }
75
+ if (word.endsWith('sses')) {
76
+ return word.slice(0, -2);
77
+ }
78
+ if (word.endsWith('xes')) {
79
+ return word.slice(0, -2);
80
+ }
81
+ if (word.endsWith('zes')) {
82
+ return word.slice(0, -3);
83
+ }
84
+ if (word.endsWith('ches')) {
85
+ return word.slice(0, -2);
86
+ }
87
+ if (word.endsWith('shes')) {
88
+ return word.slice(0, -2);
89
+ }
90
+ if (word.endsWith('s')) {
91
+ return word.slice(0, -1);
92
+ }
93
+ return word;
94
+ };
95
+ const parseUrlParams = pathname => {
96
+ const segments = pathname.split('/').filter(Boolean);
97
+ const params = {};
98
+ for (let i = 0; i < segments.length - 1; i += 2) {
99
+ params[`${singularize(segments[i])}Id`] = segments[i + 1];
100
+ }
101
+ return params;
102
+ };
71
103
  class HistoryRoute extends _Component.Component {
72
104
  constructor(props) {
73
105
  super(props);
@@ -166,9 +198,16 @@ const goTo = (path = '/', replace) => {
166
198
  }
167
199
  };
168
200
  exports.goTo = goTo;
201
+ const getUrlParams = key => {
202
+ const params = parseUrlParams(window.location.pathname);
203
+ return params[key] ?? null;
204
+ };
205
+ const getAllUrlParamNames = () => Object.keys(parseUrlParams(window.location.pathname));
169
206
  const History = {
170
207
  Link: HistoryLink,
171
208
  Redirect: HistoryRedirect,
172
- Route: HistoryRoute
209
+ Route: HistoryRoute,
210
+ getUrlParams,
211
+ getAllUrlParamNames
173
212
  };
174
213
  var _default = exports.default = History;
@@ -49,6 +49,16 @@ const IntlProvider = ({
49
49
  return undefined;
50
50
  }
51
51
  };
52
+ const interpolateValues = (text, values) => {
53
+ let result = text;
54
+ Object.keys(values).forEach(key => {
55
+ const variablePattern = `{${key}}`;
56
+ if (result.indexOf(variablePattern) > -1) {
57
+ result = result.replace(new RegExp(`\\{${key}\\}`, 'g'), String(values[key]));
58
+ }
59
+ });
60
+ return result;
61
+ };
52
62
  const FormattedMessage = ({
53
63
  id,
54
64
  values,
@@ -58,7 +68,7 @@ const FormattedMessage = ({
58
68
  messages
59
69
  }
60
70
  }) => {
61
- let textValue = '';
71
+ let textValue;
62
72
  try {
63
73
  if (messages && messages[id]) {
64
74
  textValue = messages[id];
@@ -71,12 +81,7 @@ const FormattedMessage = ({
71
81
  throw new Error('No text or fallback value to return.');
72
82
  } else {
73
83
  if (values && typeof values === 'object' && values !== null) {
74
- Object.keys(values).forEach(key => {
75
- const variablePattern = `{${key}}`;
76
- if (textValue.indexOf(variablePattern) > -1) {
77
- textValue = textValue.replace(variablePattern, String(values[key]));
78
- }
79
- });
84
+ textValue = interpolateValues(textValue, values);
80
85
  }
81
86
  return (0, _elements.createElement)(_elements.TEXT_ELEMENT, {
82
87
  nodeValue: textValue
@@ -104,12 +109,7 @@ const formatMessage = (id, values, defaultMessage) => {
104
109
  console.error(err);
105
110
  }
106
111
  if (values && typeof values === 'object' && values !== null) {
107
- Object.keys(values).forEach(key => {
108
- const variablePattern = `{${key}}`;
109
- if (textValue.indexOf(variablePattern) > -1) {
110
- textValue = textValue.replace(variablePattern, String(values[key]));
111
- }
112
- });
112
+ textValue = interpolateValues(textValue, values);
113
113
  }
114
114
  return textValue;
115
115
  };
package/dist/index.d.ts CHANGED
@@ -83,6 +83,8 @@ declare const Anu: {
83
83
  };
84
84
  isAnuComponent?: boolean;
85
85
  };
86
+ getUrlParams: (key: string) => string | null;
87
+ getAllUrlParamNames: () => string[];
86
88
  };
87
89
  Intl: {
88
90
  abbreviateNumber: (value: number, options?: import(".").AbbreviateNumberOptions) => string | number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anu-verzum",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "A \"React-like\" UI library that supports JSX syntax, Redux-like state management, array-rendering, i18n, routing and many more.",
5
5
  "keywords": [
6
6
  "anu-verzum",