@jinntec/fore 3.1.0 → 3.1.2

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/fore-dev.js CHANGED
@@ -1,4 +1,4 @@
1
- /* Version: 3.1.0 - May 20, 2026 13:19:57 */
1
+ /* Version: 3.1.2 - May 27, 2026 14:39:35 */
2
2
  function t$2(t, s, r, i) {
3
3
  const n = {
4
4
  op: s,
@@ -21574,10 +21574,8 @@ class FxModel extends HTMLElement {
21574
21574
  const instance = model.getInstance(instanceId);
21575
21575
  const fore = model.formElement;
21576
21576
  if (fore?.createNodes && (node === null || node === undefined)) {
21577
- const mi = new ModelItem(undefined, ref, null, null, instanceId, fore);
21578
- mi.isSynthetic = true;
21579
- model.registerModelItem(mi);
21580
- return mi;
21577
+ // Do not create the model item. It may be exchanged later when create-nodes actually made the node
21578
+ return null;
21581
21579
  }
21582
21580
  if (node === null || node === undefined) return null;
21583
21581
  let targetNode = Array.isArray(node) ? node[0] : node;
@@ -25307,6 +25305,17 @@ const dirtyStates = {
25307
25305
  DIRTY: 'dirty'
25308
25306
  };
25309
25307
 
25308
+ /*
25309
+ * Determine whether a string is a valid Name
25310
+ *
25311
+ * @param {string} name
25312
+ * @returns {boolean} whether the name is a valid one
25313
+ */
25314
+ function isValidName(name) {
25315
+ const result = new DOMParser().parseFromString(`<${name}/>`, 'application/xml');
25316
+ return result.querySelector('parsererror') === null;
25317
+ }
25318
+
25310
25319
  /**
25311
25320
  * Main class for Fore.Outermost container element for each Fore application.
25312
25321
  *
@@ -25470,7 +25479,7 @@ class FxFore extends HTMLElement {
25470
25479
  this._createRepeatsFromAttributes();
25471
25480
  this.inited = true;
25472
25481
  };
25473
- this.version = 'Version: 3.1.0 - built on May 20, 2026 13:19:57';
25482
+ this.version = 'Version: 3.1.2 - built on May 27, 2026 14:39:35';
25474
25483
 
25475
25484
  /**
25476
25485
  * @type {import('./fx-model.js').FxModel}
@@ -27053,7 +27062,44 @@ class FxFore extends HTMLElement {
27053
27062
  predicates
27054
27063
  };
27055
27064
  };
27056
- const steps = xpath.split('/').map(step => step.trim()).filter(step => step && step !== '.');
27065
+ const splitSteps = xpath => {
27066
+ /**
27067
+ * @type {string[]}
27068
+ */
27069
+ const steps = [];
27070
+ let scratch = '';
27071
+ let isInPredicate = false;
27072
+ for (const char of xpath.split('')) {
27073
+ if (char === '[') {
27074
+ isInPredicate = true;
27075
+ scratch += char;
27076
+ continue;
27077
+ }
27078
+ if (char === ']') {
27079
+ scratch += char;
27080
+ isInPredicate = false;
27081
+ continue;
27082
+ }
27083
+ if (!isInPredicate) {
27084
+ // Just add to the scratch. Do not check for slashes within predicates
27085
+ if (char === '/') {
27086
+ // Consume this path step
27087
+ if (scratch) {
27088
+ steps.push(scratch);
27089
+ }
27090
+ scratch = '';
27091
+ continue;
27092
+ }
27093
+ }
27094
+ scratch += char;
27095
+ }
27096
+ if (scratch) {
27097
+ // Flush it
27098
+ steps.push(scratch);
27099
+ }
27100
+ return steps;
27101
+ };
27102
+ const steps = splitSteps(xpath).map(step => step.trim()).filter(step => step && step !== '.');
27057
27103
  if (!steps.length) return null;
27058
27104
  let subtreeRoot = null;
27059
27105
  let current = null;
@@ -27066,6 +27112,11 @@ class FxFore extends HTMLElement {
27066
27112
  continue;
27067
27113
  }
27068
27114
  const parsed = parseName(token);
27115
+ if (!isValidName(parsed.localName)) {
27116
+ // This did not result in a valid name. Stop.
27117
+ console.warn(`Creating node for the XPath ${xpath} failed because the part ${parsed.localName} is not a valid Name.`);
27118
+ return;
27119
+ }
27069
27120
  if (parsed.isAttribute) {
27070
27121
  if (!current) {
27071
27122
  const attr = ownerDoc.createAttribute(parsed.localName);
package/dist/fore.js CHANGED
@@ -1,4 +1,4 @@
1
- /* Version: 3.1.0 - May 20, 2026 13:19:56 */
1
+ /* Version: 3.1.2 - May 27, 2026 14:39:34 */
2
2
  function t$2(t, s, r, i) {
3
3
  const n = {
4
4
  op: s,
@@ -21553,10 +21553,8 @@ class FxModel extends HTMLElement {
21553
21553
  const instance = model.getInstance(instanceId);
21554
21554
  const fore = model.formElement;
21555
21555
  if (fore?.createNodes && (node === null || node === undefined)) {
21556
- const mi = new ModelItem(undefined, ref, null, null, instanceId, fore);
21557
- mi.isSynthetic = true;
21558
- model.registerModelItem(mi);
21559
- return mi;
21556
+ // Do not create the model item. It may be exchanged later when create-nodes actually made the node
21557
+ return null;
21560
21558
  }
21561
21559
  if (node === null || node === undefined) return null;
21562
21560
  let targetNode = Array.isArray(node) ? node[0] : node;
@@ -25256,6 +25254,17 @@ const dirtyStates = {
25256
25254
  DIRTY: 'dirty'
25257
25255
  };
25258
25256
 
25257
+ /*
25258
+ * Determine whether a string is a valid Name
25259
+ *
25260
+ * @param {string} name
25261
+ * @returns {boolean} whether the name is a valid one
25262
+ */
25263
+ function isValidName(name) {
25264
+ const result = new DOMParser().parseFromString(`<${name}/>`, 'application/xml');
25265
+ return result.querySelector('parsererror') === null;
25266
+ }
25267
+
25259
25268
  /**
25260
25269
  * Main class for Fore.Outermost container element for each Fore application.
25261
25270
  *
@@ -25416,7 +25425,7 @@ class FxFore extends HTMLElement {
25416
25425
  this._createRepeatsFromAttributes();
25417
25426
  this.inited = true;
25418
25427
  };
25419
- this.version = 'Version: 3.1.0 - built on May 20, 2026 13:19:56';
25428
+ this.version = 'Version: 3.1.2 - built on May 27, 2026 14:39:34';
25420
25429
 
25421
25430
  /**
25422
25431
  * @type {import('./fx-model.js').FxModel}
@@ -26982,7 +26991,44 @@ class FxFore extends HTMLElement {
26982
26991
  predicates
26983
26992
  };
26984
26993
  };
26985
- const steps = xpath.split('/').map(step => step.trim()).filter(step => step && step !== '.');
26994
+ const splitSteps = xpath => {
26995
+ /**
26996
+ * @type {string[]}
26997
+ */
26998
+ const steps = [];
26999
+ let scratch = '';
27000
+ let isInPredicate = false;
27001
+ for (const char of xpath.split('')) {
27002
+ if (char === '[') {
27003
+ isInPredicate = true;
27004
+ scratch += char;
27005
+ continue;
27006
+ }
27007
+ if (char === ']') {
27008
+ scratch += char;
27009
+ isInPredicate = false;
27010
+ continue;
27011
+ }
27012
+ if (!isInPredicate) {
27013
+ // Just add to the scratch. Do not check for slashes within predicates
27014
+ if (char === '/') {
27015
+ // Consume this path step
27016
+ if (scratch) {
27017
+ steps.push(scratch);
27018
+ }
27019
+ scratch = '';
27020
+ continue;
27021
+ }
27022
+ }
27023
+ scratch += char;
27024
+ }
27025
+ if (scratch) {
27026
+ // Flush it
27027
+ steps.push(scratch);
27028
+ }
27029
+ return steps;
27030
+ };
27031
+ const steps = splitSteps(xpath).map(step => step.trim()).filter(step => step && step !== '.');
26986
27032
  if (!steps.length) return null;
26987
27033
  let subtreeRoot = null;
26988
27034
  let current = null;
@@ -26995,6 +27041,10 @@ class FxFore extends HTMLElement {
26995
27041
  continue;
26996
27042
  }
26997
27043
  const parsed = parseName(token);
27044
+ if (!isValidName(parsed.localName)) {
27045
+ // This did not result in a valid name. Stop.
27046
+ return;
27047
+ }
26998
27048
  if (parsed.isAttribute) {
26999
27049
  if (!current) {
27000
27050
  const attr = ownerDoc.createAttribute(parsed.localName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jinntec/fore",
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "description": "Fore - declarative user interfaces in plain HTML",
5
5
  "module": "./index.js",
6
6
  "publishConfig": {
package/src/fx-fore.js CHANGED
@@ -29,6 +29,17 @@ async function waitForFunctionLibs(rootEl) {
29
29
  await Promise.all(libs.map(l => (l.readyPromise ? l.readyPromise : Promise.resolve())));
30
30
  }
31
31
 
32
+ /*
33
+ * Determine whether a string is a valid Name
34
+ *
35
+ * @param {string} name
36
+ * @returns {boolean} whether the name is a valid one
37
+ */
38
+ function isValidName(name) {
39
+ const result = new DOMParser().parseFromString(`<${name}/>`, 'application/xml');
40
+ return result.querySelector('parsererror') === null;
41
+ }
42
+
32
43
  /**
33
44
  * Main class for Fore.Outermost container element for each Fore application.
34
45
  *
@@ -1948,8 +1959,47 @@ export class FxFore extends HTMLElement {
1948
1959
  return { token, predicates };
1949
1960
  };
1950
1961
 
1951
- const steps = xpath
1952
- .split('/')
1962
+ const splitSteps = xpath => {
1963
+ /**
1964
+ * @type {string[]}
1965
+ */
1966
+ const steps = [];
1967
+ let scratch = '';
1968
+ let isInPredicate = false;
1969
+ for (const char of xpath.split('')) {
1970
+ if (char === '[') {
1971
+ isInPredicate = true;
1972
+ scratch += char;
1973
+ continue;
1974
+ }
1975
+ if (char === ']') {
1976
+ scratch += char;
1977
+ isInPredicate = false;
1978
+ continue;
1979
+ }
1980
+ if (!isInPredicate) {
1981
+ // Just add to the scratch. Do not check for slashes within predicates
1982
+ if (char === '/') {
1983
+ // Consume this path step
1984
+ if (scratch) {
1985
+ steps.push(scratch);
1986
+ }
1987
+ scratch = '';
1988
+ continue;
1989
+ }
1990
+ }
1991
+ scratch += char;
1992
+ }
1993
+
1994
+ if (scratch) {
1995
+ // Flush it
1996
+ steps.push(scratch);
1997
+ }
1998
+
1999
+ return steps;
2000
+ };
2001
+
2002
+ const steps = splitSteps(xpath)
1953
2003
  .map(step => step.trim())
1954
2004
  .filter(step => step && step !== '.');
1955
2005
 
@@ -1966,6 +2016,14 @@ export class FxFore extends HTMLElement {
1966
2016
 
1967
2017
  const parsed = parseName(token);
1968
2018
 
2019
+ if (!isValidName(parsed.localName)) {
2020
+ // This did not result in a valid name. Stop.
2021
+ console.warn(
2022
+ `Creating node for the XPath ${xpath} failed because the part ${parsed.localName} is not a valid Name.`,
2023
+ );
2024
+ return;
2025
+ }
2026
+
1969
2027
  if (parsed.isAttribute) {
1970
2028
  if (!current) {
1971
2029
  const attr = ownerDoc.createAttribute(parsed.localName);
package/src/fx-model.js CHANGED
@@ -133,10 +133,8 @@ export class FxModel extends HTMLElement {
133
133
  const fore = model.formElement;
134
134
 
135
135
  if (fore?.createNodes && (node === null || node === undefined)) {
136
- const mi = new ModelItem(undefined, ref, null, null, instanceId, fore);
137
- mi.isSynthetic = true;
138
- model.registerModelItem(mi);
139
- return mi;
136
+ // Do not create the model item. It may be exchanged later when create-nodes actually made the node
137
+ return null;
140
138
  }
141
139
  if (node === null || node === undefined) return null;
142
140
 
@@ -159,8 +157,10 @@ export class FxModel extends HTMLElement {
159
157
  }
160
158
 
161
159
  const isLensObject =
162
- !!targetNode && typeof targetNode === 'object' &&
163
- typeof targetNode.get === 'function' && typeof targetNode.set === 'function';
160
+ !!targetNode &&
161
+ typeof targetNode === 'object' &&
162
+ typeof targetNode.get === 'function' &&
163
+ typeof targetNode.set === 'function';
164
164
 
165
165
  // If ModelItem for same path exists, RETARGET it (node OR lens)
166
166
  if (path) {
@@ -182,12 +182,12 @@ export class FxModel extends HTMLElement {
182
182
  }
183
183
 
184
184
  const mi = new ModelItem(
185
- path,
186
- ref,
187
- targetNode,
188
- model.getBindForElement(targetNode),
189
- instanceId,
190
- fore,
185
+ path,
186
+ ref,
187
+ targetNode,
188
+ model.getBindForElement(targetNode),
189
+ instanceId,
190
+ fore,
191
191
  );
192
192
  mi.isSynthetic = true;
193
193
 
@@ -231,7 +231,8 @@ export class FxModel extends HTMLElement {
231
231
  const defInst = this.getDefaultInstance();
232
232
  if (defInst) {
233
233
  const t = (defInst.getAttribute && defInst.getAttribute('type')) || defInst.type;
234
- bindings.default = t === 'json' ? defInst.getInstanceData() : defInst.getDefaultContext();
234
+ bindings.default =
235
+ t === 'json' ? defInst.getInstanceData() : defInst.getDefaultContext();
235
236
  }
236
237
  } catch (_e) {
237
238
  // ignore
@@ -734,14 +735,14 @@ export class FxModel extends HTMLElement {
734
735
 
735
736
  // Path lookup
736
737
  if (typeof nodeOrPath === 'string') {
737
- const key = nodeOrPath.includes(':') ? nodeOrPath.substring(0, nodeOrPath.indexOf(':')) : nodeOrPath;
738
+ const key = nodeOrPath.includes(':')
739
+ ? nodeOrPath.substring(0, nodeOrPath.indexOf(':'))
740
+ : nodeOrPath;
738
741
  return this.modelItems.find(mi => mi.path === key) || null;
739
742
  }
740
743
 
741
744
  // Node/lens lookup
742
- return (
743
- this.modelItems.find(mi => mi.node === nodeOrPath || mi.lens === nodeOrPath) || null
744
- );
745
+ return this.modelItems.find(mi => mi.node === nodeOrPath || mi.lens === nodeOrPath) || null;
745
746
  }
746
747
 
747
748
  /**
@@ -791,9 +792,9 @@ export class FxModel extends HTMLElement {
791
792
  // ### lookup in parent Fore if present (shared instances)
792
793
  if (!found) {
793
794
  const parentFore =
794
- this.fore.parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE
795
- ? this.fore.parentNode.host.closest('fx-fore')
796
- : this.fore.parentNode.closest('fx-fore');
795
+ this.fore.parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE
796
+ ? this.fore.parentNode.host.closest('fx-fore')
797
+ : this.fore.parentNode.closest('fx-fore');
797
798
 
798
799
  if (parentFore) {
799
800
  const parentInstances = parentFore.getModel().instances;