sygnal 2.8.0 → 2.8.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/index.cjs.js CHANGED
@@ -3283,8 +3283,10 @@ class Component {
3283
3283
  };
3284
3284
  }
3285
3285
 
3286
+ const componentNumber = COMPONENT_COUNT++;
3287
+
3286
3288
  this.addCalculated = this.createMemoizedAddCalculated();
3287
- this.log = makeLog(name);
3289
+ this.log = makeLog(`${componentNumber} | ${name}`);
3288
3290
 
3289
3291
  this.initIntent$();
3290
3292
  this.initAction$();
@@ -3299,11 +3301,9 @@ class Component {
3299
3301
  this.initVdom$();
3300
3302
  this.initSinks();
3301
3303
 
3302
- this.sinks.__index = COMPONENT_COUNT++;
3304
+ this.sinks.__index = componentNumber;
3303
3305
 
3304
- if (debug) {
3305
- console.log(`[${ this.name }] Instantiated (#${ this.sinks.__index })`);
3306
- }
3306
+ this.log(`Instantiated`, true);
3307
3307
  }
3308
3308
 
3309
3309
  get debug() {
@@ -3358,7 +3358,7 @@ class Component {
3358
3358
  const hydrate$ = initialApiData.map(data => ({ type: HYDRATE_ACTION, data }));
3359
3359
 
3360
3360
  this.action$ = xs$1.merge(wrapped$, hydrate$)
3361
- .compose(this.log(({ type }) => `Action triggered: <${ type }>`));
3361
+ .compose(this.log(({ type }) => `<${ type }> Action triggered`));
3362
3362
  }
3363
3363
 
3364
3364
  initResponse$() {
@@ -3408,7 +3408,7 @@ class Component {
3408
3408
  console.log(`${ timestamp } ${ ip } ${ req.method } ${ req.url }`);
3409
3409
 
3410
3410
  if (this.debug) {
3411
- this.action$.setDebugListener({next: ({ type }) => console.log(`[${ this.name }] Action from ${ this.requestSourceName } request: <${ type }>`)});
3411
+ this.action$.setDebugListener({next: ({ type }) => this.log(`[${ this.name }] Action from ${ this.requestSourceName } request: <${ type }>`, true)});
3412
3412
  }
3413
3413
 
3414
3414
  if (actionType === 'function') {
@@ -3565,10 +3565,10 @@ class Component {
3565
3565
  const wrapped$ = on$
3566
3566
  .compose(this.log(data => {
3567
3567
  if (isStateSink) {
3568
- return `State reducer added: <${ action }>`
3568
+ return `<${ action }> State reducer added`
3569
3569
  } else {
3570
3570
  const extra = data && (data.type || data.command || data.name || data.key || (Array.isArray(data) && 'Array') || data);
3571
- return `Data sent to [${ sink }]: <${ action }> ${ JSON.stringify(extra) }`
3571
+ return `<${ action }> Data sent to [${ sink }]: ${ JSON.stringify(extra).replaceAll('"', '') }`
3572
3572
  }
3573
3573
  }));
3574
3574
 
@@ -3691,6 +3691,7 @@ class Component {
3691
3691
 
3692
3692
  this.vdom$ = renderParameters$
3693
3693
  .map(this.view)
3694
+ .compose(this.log('View rendered'))
3694
3695
  .map(vDom => vDom || { sel: 'div', data: {}, children: [] })
3695
3696
  .compose(this.instantiateSubComponents.bind(this))
3696
3697
  .filter(val => val !== undefined)
@@ -3731,6 +3732,7 @@ class Component {
3731
3732
  // push the "next" action request into the action$ stream
3732
3733
  rootAction$.shamefullySendNext({ type, data: _data });
3733
3734
  }, delay);
3735
+ this.log(`<${ name }> Triggered a next() action: <${ type }> ${ delay }ms delay`, true);
3734
3736
  };
3735
3737
 
3736
3738
  let data = action.data;
@@ -3827,37 +3829,19 @@ class Component {
3827
3829
  const enhancedState = state && state.isolateSource(state, { get: state => this.addCalculated(state) });
3828
3830
  const stateStream = (enhancedState && enhancedState.stream) || xs$1.never();
3829
3831
 
3830
- const objRepeatChecker = (a, b) => {
3831
- const { state, sygnalFactory, __props, __children, __context, ...sanitized } = a;
3832
- const keys = Object.keys(sanitized);
3833
- if (keys.length === 0) {
3834
- const { state, sygnalFactory, __props, __children, __context, ...sanitizedB } = b;
3835
- return Object.keys(sanitizedB).length === 0
3836
- }
3837
- return keys.every(key => a[key] === b[key])
3838
- };
3839
3832
 
3840
- const arrRepeatChecker = (a, b) => {
3841
- if (a === b) return true
3842
- if (a.length !== b.length) return false
3843
- for (let i=0; i < a.length; i++) {
3844
- if (a[i] !== b[i]) return false
3845
- }
3846
- return true
3847
- };
3848
-
3849
- renderParams.state = stateStream.compose(_default$5(objRepeatChecker));
3833
+ renderParams.state = stateStream.compose(_default$5(objIsEqual));
3850
3834
 
3851
3835
  if (this.sources.props$) {
3852
- renderParams.__props = this.sources.props$.compose(_default$5(objRepeatChecker));
3836
+ renderParams.__props = this.sources.props$.compose(_default$5(objIsEqual));
3853
3837
  }
3854
3838
 
3855
3839
  if (this.sources.children$) {
3856
- renderParams.__children = this.sources.children$.compose(_default$5(arrRepeatChecker));
3840
+ renderParams.__children = this.sources.children$.compose(_default$5(objIsEqual));
3857
3841
  }
3858
3842
 
3859
3843
  if (this.context$) {
3860
- renderParams.__context = this.context$.compose(_default$5(objRepeatChecker));
3844
+ renderParams.__context = this.context$.compose(_default$5(objIsEqual));
3861
3845
  }
3862
3846
 
3863
3847
  const names = [];
@@ -3869,11 +3853,15 @@ class Component {
3869
3853
  });
3870
3854
 
3871
3855
  const combined = xs$1.combine(...streams)
3856
+ .compose(_default$2(1))
3872
3857
  // map the streams from an array back to an object with the render parameter names as the keys
3873
3858
  .map(arr => {
3874
3859
  const params = names.reduce((acc, name, index) => {
3875
3860
  acc[name] = arr[index];
3876
3861
  if (name === 'state') acc[this.stateSourceName] = arr[index];
3862
+ if (name === '__props') acc.props = arr[index];
3863
+ if (name === '__children') acc.children = arr[index];
3864
+ if (name === '__context') acc.context = arr[index];
3877
3865
  return acc
3878
3866
  }, {});
3879
3867
  return params
@@ -3895,6 +3883,7 @@ class Component {
3895
3883
  }
3896
3884
 
3897
3885
  const sinkArrsByType = {};
3886
+ let newInstanceCount = 0;
3898
3887
 
3899
3888
  const newComponents = entries.reduce((acc, [id, el]) => {
3900
3889
  const data = el.data;
@@ -3934,6 +3923,8 @@ class Component {
3934
3923
  instantiator = this.instantiateCustomComponent.bind(this);
3935
3924
  }
3936
3925
 
3926
+ newInstanceCount++;
3927
+
3937
3928
  const sink$ = instantiator(el, props$, children$);
3938
3929
 
3939
3930
  sink$[this.DOMSourceName] = sink$[this.DOMSourceName] ? this.makeCoordinatedSubComponentDomSink(sink$[this.DOMSourceName]) : xs$1.never();
@@ -3953,18 +3944,18 @@ class Component {
3953
3944
 
3954
3945
  this.newSubComponentSinks(mergedSinksByType);
3955
3946
 
3947
+ if (newInstanceCount > 0) this.log(`New sub components instantiated: ${ newInstanceCount }`, true);
3948
+
3956
3949
  return newComponents
3957
3950
  }, {})
3958
3951
  }
3959
3952
 
3960
3953
  makeCoordinatedSubComponentDomSink(domSink$) {
3961
3954
  const remembered$ = domSink$.remember();
3962
- const repeatChecker = (a, b) => JSON.stringify(a) === JSON.stringify(b);
3963
3955
 
3964
3956
  const coordinated = this.sources[this.stateSourceName].stream
3965
- .compose(_default$5(repeatChecker))
3957
+ .compose(_default$5(objIsEqual))
3966
3958
  .map(state => remembered$)
3967
- .compose(_default$2(10))
3968
3959
  .flatten()
3969
3960
  .debug(_ => this.triggerSubComponentsRendered())
3970
3961
  .remember();
@@ -4214,7 +4205,7 @@ class Component {
4214
4205
 
4215
4206
  renderVdom(componentInstances$) {
4216
4207
  return xs$1.combine(this.subComponentsRendered$, componentInstances$)
4217
- .compose(_default$2(5))
4208
+ .compose(_default$2(1))
4218
4209
  .map(([_, components]) => {
4219
4210
  const componentNames = Object.keys(this.components);
4220
4211
 
@@ -4235,7 +4226,7 @@ class Component {
4235
4226
  if (vdom$.length === 0) return xs$1.of(root)
4236
4227
 
4237
4228
  return xs$1.combine(...vdom$)
4238
- .compose(_default$2(10))
4229
+ .compose(_default$2(1))
4239
4230
  .map(vdoms => {
4240
4231
  const withIds = vdoms.reduce((acc, vdom, index) => {
4241
4232
  acc[ids[index]] = vdom;
@@ -4249,7 +4240,6 @@ class Component {
4249
4240
  .flatten()
4250
4241
  .filter(val => !!val)
4251
4242
  .remember()
4252
- .compose(this.log('View Rendered'))
4253
4243
  }
4254
4244
 
4255
4245
  }
@@ -4273,21 +4263,28 @@ class Component {
4273
4263
  * ONLY outputs if the global `DEBUG` variable is set to `true`
4274
4264
  */
4275
4265
  function makeLog (context) {
4276
- return function (msg) {
4266
+ return function (msg, immediate=false) {
4277
4267
  const fixedMsg = (typeof msg === 'function') ? msg : _ => msg;
4278
- return stream => {
4279
- return stream.debug(msg => {
4280
- if (this.debug) {
4281
- console.log(`[${context}] ${fixedMsg(msg)}`);
4282
- }
4283
- })
4268
+ if (immediate) {
4269
+ if (this.debug) {
4270
+ console.log(`[${context}] ${fixedMsg(msg)}`);
4271
+ }
4272
+ return
4273
+ } else {
4274
+ return stream => {
4275
+ return stream.debug(msg => {
4276
+ if (this.debug) {
4277
+ console.log(`[${context}] ${fixedMsg(msg)}`);
4278
+ }
4279
+ })
4280
+ }
4284
4281
  }
4285
4282
  }
4286
4283
  }
4287
4284
 
4288
4285
 
4289
4286
 
4290
- function getComponents(currentElement, componentNames, depth=0, index=0) {
4287
+ function getComponents(currentElement, componentNames, depth=0, index=0, parentId) {
4291
4288
  if (!currentElement) return {}
4292
4289
 
4293
4290
  if (currentElement.data?.componentsProcessed) return {}
@@ -4302,9 +4299,10 @@ function getComponents(currentElement, componentNames, depth=0, index=0) {
4302
4299
  const children = currentElement.children || [];
4303
4300
 
4304
4301
  let found = {};
4305
-
4302
+
4303
+ let id = parentId;
4306
4304
  if (isComponent) {
4307
- const id = getComponentIdFromElement(currentElement, depth, index);
4305
+ id = getComponentIdFromElement(currentElement, depth, index, parentId);
4308
4306
  if (isCollection) {
4309
4307
  if (!props.of) throw new Error(`Collection element missing required 'component' property`)
4310
4308
  if (typeof props.of !== 'string' && typeof props.of !== 'function') throw new Error(`Invalid 'component' property of collection element: found ${ typeof props.of } requires string or component factory function`)
@@ -4327,7 +4325,7 @@ function getComponents(currentElement, componentNames, depth=0, index=0) {
4327
4325
  }
4328
4326
 
4329
4327
  if (children.length > 0) {
4330
- children.map((child, i) => getComponents(child, componentNames, depth + 1, index + i))
4328
+ children.map((child, i) => getComponents(child, componentNames, depth + 1, index + i, id))
4331
4329
  .forEach((child) => {
4332
4330
  Object.entries(child).forEach(([id, el]) => found[id] = el);
4333
4331
  });
@@ -4336,7 +4334,7 @@ function getComponents(currentElement, componentNames, depth=0, index=0) {
4336
4334
  return found
4337
4335
  }
4338
4336
 
4339
- function injectComponents(currentElement, components, componentNames, depth=0, index=0) {
4337
+ function injectComponents(currentElement, components, componentNames, depth=0, index=0, parentId) {
4340
4338
  if (!currentElement) return
4341
4339
  if (currentElement.data?.componentsInjected) return currentElement
4342
4340
  if (depth === 0 && currentElement.data) currentElement.data.componentsInjected = true;
@@ -4349,8 +4347,9 @@ function injectComponents(currentElement, components, componentNames, depth=0, i
4349
4347
  (currentElement.data && currentElement.data.props) || {};
4350
4348
  const children = currentElement.children || [];
4351
4349
 
4350
+ let id = parentId;
4352
4351
  if (isComponent) {
4353
- const id = getComponentIdFromElement(currentElement, depth, index);
4352
+ id = getComponentIdFromElement(currentElement, depth, index, parentId);
4354
4353
  const component = components[id];
4355
4354
  if (isCollection) {
4356
4355
  currentElement.sel = 'div';
@@ -4362,28 +4361,21 @@ function injectComponents(currentElement, components, componentNames, depth=0, i
4362
4361
  return component
4363
4362
  }
4364
4363
  } else if (children.length > 0) {
4365
- currentElement.children = children.map((child, i) => injectComponents(child, components, componentNames, depth + 1, index + i)).flat();
4364
+ currentElement.children = children.map((child, i) => injectComponents(child, components, componentNames, depth + 1, index + i, id)).flat();
4366
4365
  return currentElement
4367
4366
  } else {
4368
4367
  return currentElement
4369
4368
  }
4370
4369
  }
4371
4370
 
4372
- const selMap = new Map();
4373
- function getComponentIdFromElement(el, depth, index) {
4374
- const sel = el.sel;
4375
- const name = typeof sel === 'string' ? sel : 'functionComponent';
4376
- let base = selMap.get(sel);
4377
- if (!base) {
4378
- const date = Date.now();
4379
- const rand = Math.floor(Math.random() * 10000);
4380
- base = `${date}-${rand}`;
4381
- selMap.set(sel, base);
4382
- }
4383
- const uid = `${base}-${depth}-${index}`;
4384
- const props = (el.data && el.data.props) || {};
4385
- const id = (props.id && JSON.stringify(props.id)) || uid;
4386
- const fullId = `${ name }::${ id }`;
4371
+ function getComponentIdFromElement(el, depth, index, parentId) {
4372
+ const sel = el.sel;
4373
+ const name = typeof sel === 'string' ? sel : 'functionComponent';
4374
+ const uid = `${depth}:${index}`;
4375
+ const props = el.data?.props || {};
4376
+ const id = (props.id && JSON.stringify(props.id).replaceAll('"', '')) || uid;
4377
+ const parentString = parentId ? `${ parentId }|` : '';
4378
+ const fullId = `${ parentString }${ name }::${ id }`;
4387
4379
  return fullId
4388
4380
  }
4389
4381
 
@@ -4393,6 +4385,65 @@ function deepCopyVdom(obj) {
4393
4385
  return { ...obj, children: Array.isArray(obj.children) ? obj.children.map(deepCopyVdom) : undefined, data: obj.data && { ...obj.data, componentsInjected: false } }
4394
4386
  }
4395
4387
 
4388
+ function objIsEqual(objA, objB, maxDepth = 5, depth = 0) {
4389
+ const obj1 = sanitizeObject(objA);
4390
+ const obj2 = sanitizeObject(objB);
4391
+ // Base case: if the current depth exceeds maxDepth, return true
4392
+ if (depth > maxDepth) {
4393
+ return false;
4394
+ }
4395
+
4396
+ // If both are the same object or are both exactly null or undefined
4397
+ if (obj1 === obj2) {
4398
+ return true;
4399
+ }
4400
+
4401
+ // If either is not an object (null, undefined, or primitive), directly compare
4402
+ if (typeof obj1 !== 'object' || obj1 === null || typeof obj2 !== 'object' || obj2 === null) {
4403
+ return false;
4404
+ }
4405
+
4406
+ // Special handling for arrays
4407
+ if (Array.isArray(obj1) && Array.isArray(obj2)) {
4408
+ if (obj1.length !== obj2.length) {
4409
+ return false;
4410
+ }
4411
+ for (let i = 0; i < obj1.length; i++) {
4412
+ if (!isEqual(obj1[i], obj2[i], maxDepth, depth + 1)) {
4413
+ return false;
4414
+ }
4415
+ }
4416
+ return true;
4417
+ }
4418
+
4419
+ // Get keys of both objects
4420
+ const keys1 = Object.keys(obj1);
4421
+ const keys2 = Object.keys(obj2);
4422
+
4423
+ // Check if the number of properties is different
4424
+ if (keys1.length !== keys2.length) {
4425
+ return false;
4426
+ }
4427
+
4428
+ // Recursively check each property
4429
+ for (const key of keys1) {
4430
+ if (!keys2.includes(key)) {
4431
+ return false;
4432
+ }
4433
+ if (!objIsEqual(obj1[key], obj2[key], maxDepth, depth + 1)) {
4434
+ return false;
4435
+ }
4436
+ }
4437
+
4438
+ return true;
4439
+ }
4440
+
4441
+ function sanitizeObject(obj) {
4442
+ if (typeof obj !== 'object' || obj === null) return obj
4443
+ const {state, of, from, _reqId, _action, __props, __children, __context, ...sanitized} = obj;
4444
+ return sanitized
4445
+ }
4446
+
4396
4447
  function driverFromAsync(promiseReturningFunction, opts = {}) {
4397
4448
  const {
4398
4449
  selector: selectorProperty = 'category',