spytial-core 1.4.10 → 1.4.11-beta.3

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.
@@ -94137,9 +94137,12 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
94137
94137
  if (!relation) {
94138
94138
  throw new Error(`Cannot remove tuple: relation '${relationId}' not found`);
94139
94139
  }
94140
- const tupleKey = JSON.stringify(tuple);
94140
+ const tupleMatches = (t1, t2) => {
94141
+ if (t1.atoms.length !== t2.atoms.length) return false;
94142
+ return t1.atoms.every((atom, i) => atom === t2.atoms[i]);
94143
+ };
94141
94144
  const initialLength = relation.tuples.length;
94142
- relation.tuples = relation.tuples.filter((t) => JSON.stringify(t) !== tupleKey);
94145
+ relation.tuples = relation.tuples.filter((t) => !tupleMatches(t, tuple));
94143
94146
  if (relation.tuples.length === initialLength) {
94144
94147
  throw new Error(`Tuple not found in relation '${relationId}'`);
94145
94148
  }
@@ -94528,7 +94531,6 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
94528
94531
  init_layoutinstance();
94529
94532
  init_layoutspec();
94530
94533
  exports.StructuredInputGraph = class extends WebColaCnDGraph {
94531
- // Default to 2 positions
94532
94534
  constructor(dataInstance) {
94533
94535
  super();
94534
94536
  this.evaluator = null;
@@ -94537,6 +94539,16 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
94537
94539
  this.controlsContainer = null;
94538
94540
  this.customTypes = /* @__PURE__ */ new Set();
94539
94541
  this.relationAtomPositions = ["", ""];
94542
+ // Default to 2 positions
94543
+ this.currentConstraintError = null;
94544
+ // Track current constraint validation error
94545
+ // Track event listeners to prevent duplicates
94546
+ this.dataInstanceEventHandlers = {
94547
+ atomAdded: null,
94548
+ atomRemoved: null,
94549
+ relationTupleAdded: null,
94550
+ relationTupleRemoved: null
94551
+ };
94540
94552
  const instance = dataInstance || new exports.JSONDataInstance({
94541
94553
  atoms: [],
94542
94554
  relations: []
@@ -95217,6 +95229,7 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
95217
95229
  }
95218
95230
  /**
95219
95231
  * Enforce constraints and regenerate layout
95232
+ * This method validates constraints on every data update and reports UNSAT cores
95220
95233
  */
95221
95234
  async enforceConstraintsAndRegenerate() {
95222
95235
  console.log("\u{1F504} enforceConstraintsAndRegenerate() called");
@@ -95240,15 +95253,37 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
95240
95253
  const projections = {};
95241
95254
  const layoutResult = this.layoutInstance.generateLayout(this.dataInstance, projections);
95242
95255
  if (layoutResult.error) {
95243
- console.warn("\u26A0\uFE0F Constraint validation error:", layoutResult.error);
95256
+ console.warn("\u26A0\uFE0F Constraint validation error detected:", layoutResult.error);
95257
+ this.currentConstraintError = layoutResult.error;
95258
+ this.dispatchEvent(new CustomEvent("constraint-error", {
95259
+ detail: {
95260
+ error: layoutResult.error,
95261
+ layout: layoutResult.layout
95262
+ },
95263
+ bubbles: true
95264
+ }));
95265
+ console.log("\u{1F4E4} Dispatched constraint-error event with UNSAT core information");
95244
95266
  } else {
95245
- console.log("\u2705 Layout generated successfully");
95267
+ console.log("\u2705 Layout generated successfully - all constraints satisfied");
95268
+ if (this.currentConstraintError !== null) {
95269
+ console.log("\u{1F9F9} Clearing previous constraint error - constraints now satisfied");
95270
+ this.currentConstraintError = null;
95271
+ this.dispatchEvent(new CustomEvent("constraints-satisfied", {
95272
+ detail: { layout: layoutResult.layout },
95273
+ bubbles: true
95274
+ }));
95275
+ console.log("\u{1F4E4} Dispatched constraints-satisfied event");
95276
+ }
95246
95277
  }
95247
95278
  console.log("\u{1F3A8} Rendering layout...");
95248
95279
  await this.renderLayout(layoutResult.layout);
95249
95280
  console.log("\u2705 Constraints enforced and layout regenerated successfully");
95250
95281
  } catch (error) {
95251
95282
  console.error("\u274C Failed to enforce constraints and regenerate layout:", error);
95283
+ this.dispatchEvent(new CustomEvent("layout-generation-error", {
95284
+ detail: { error },
95285
+ bubbles: true
95286
+ }));
95252
95287
  }
95253
95288
  }
95254
95289
  /**
@@ -95507,24 +95542,68 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
95507
95542
  console.error("\u274C Failed to export data:", error);
95508
95543
  }
95509
95544
  }
95545
+ /**
95546
+ * Common handler for data changes that updates UI components
95547
+ * @param includeAtomPositions - Whether to update atom position selectors (needed for atom changes)
95548
+ */
95549
+ handleDataChangeUIUpdate(includeAtomPositions = false) {
95550
+ this.refreshTypesFromDataInstance();
95551
+ this.updateDeletionSelects();
95552
+ if (includeAtomPositions) {
95553
+ this.updateAtomPositions();
95554
+ }
95555
+ }
95556
+ /**
95557
+ * Common handler for data deletions that updates UI and triggers constraint validation
95558
+ * @param includeAtomPositions - Whether to update atom position selectors (needed for atom deletions)
95559
+ */
95560
+ async handleDataDeletionWithValidation(includeAtomPositions = false) {
95561
+ this.handleDataChangeUIUpdate(includeAtomPositions);
95562
+ await this.enforceConstraintsAndRegenerate();
95563
+ }
95510
95564
  /**
95511
95565
  * Set the data instance for this graph
95512
95566
  */
95513
95567
  setDataInstance(instance) {
95514
95568
  console.log("\u{1F504} Setting new data instance");
95569
+ if (this.dataInstance) {
95570
+ if (this.dataInstanceEventHandlers.atomAdded) {
95571
+ this.dataInstance.removeEventListener("atomAdded", this.dataInstanceEventHandlers.atomAdded);
95572
+ }
95573
+ if (this.dataInstanceEventHandlers.atomRemoved) {
95574
+ this.dataInstance.removeEventListener("atomRemoved", this.dataInstanceEventHandlers.atomRemoved);
95575
+ }
95576
+ if (this.dataInstanceEventHandlers.relationTupleAdded) {
95577
+ this.dataInstance.removeEventListener("relationTupleAdded", this.dataInstanceEventHandlers.relationTupleAdded);
95578
+ }
95579
+ if (this.dataInstanceEventHandlers.relationTupleRemoved) {
95580
+ this.dataInstance.removeEventListener("relationTupleRemoved", this.dataInstanceEventHandlers.relationTupleRemoved);
95581
+ }
95582
+ }
95515
95583
  this.dataInstance = instance;
95516
95584
  this.refreshTypesFromDataInstance();
95517
- instance.addEventListener("atomAdded", () => {
95518
- console.log("\u{1F4CD} Atom added to instance - updating UI");
95519
- this.refreshTypesFromDataInstance();
95520
- this.updateDeletionSelects();
95521
- this.updateAtomPositions();
95522
- });
95523
- instance.addEventListener("relationTupleAdded", () => {
95524
- console.log("\u{1F517} Relation added to instance - updating UI");
95525
- this.refreshTypesFromDataInstance();
95526
- this.updateDeletionSelects();
95527
- });
95585
+ this.dataInstanceEventHandlers.atomAdded = async () => {
95586
+ console.log("\u{1F4CD} Atom added to instance - updating UI and re-validating constraints");
95587
+ this.handleDataChangeUIUpdate(true);
95588
+ await this.enforceConstraintsAndRegenerate();
95589
+ };
95590
+ this.dataInstanceEventHandlers.relationTupleAdded = async () => {
95591
+ console.log("\u{1F517} Relation added to instance - updating UI and re-validating constraints");
95592
+ this.handleDataChangeUIUpdate(false);
95593
+ await this.enforceConstraintsAndRegenerate();
95594
+ };
95595
+ this.dataInstanceEventHandlers.atomRemoved = async () => {
95596
+ console.log("\u{1F5D1}\uFE0F Atom removed from instance - updating UI and re-validating constraints");
95597
+ await this.handleDataDeletionWithValidation(true);
95598
+ };
95599
+ this.dataInstanceEventHandlers.relationTupleRemoved = async () => {
95600
+ console.log("\u{1F5D1}\uFE0F Relation tuple removed from instance - updating UI and re-validating constraints");
95601
+ await this.handleDataDeletionWithValidation(false);
95602
+ };
95603
+ instance.addEventListener("atomAdded", this.dataInstanceEventHandlers.atomAdded);
95604
+ instance.addEventListener("relationTupleAdded", this.dataInstanceEventHandlers.relationTupleAdded);
95605
+ instance.addEventListener("atomRemoved", this.dataInstanceEventHandlers.atomRemoved);
95606
+ instance.addEventListener("relationTupleRemoved", this.dataInstanceEventHandlers.relationTupleRemoved);
95528
95607
  this.updateDeletionSelects();
95529
95608
  this.updateAtomPositions();
95530
95609
  console.log("\u2705 Data instance set successfully");
@@ -95583,18 +95662,8 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
95583
95662
  console.warn(`\u26A0\uFE0F Atom ${atomId} not found`);
95584
95663
  return;
95585
95664
  }
95586
- const remainingAtoms = atoms.filter((atom) => atom.id !== atomId);
95587
- const relations = this.dataInstance.getRelations().filter(
95588
- (rel) => !rel.tuples.some((tuple) => tuple.atoms.includes(atomId))
95589
- );
95590
- const newInstance = new exports.JSONDataInstance({
95591
- atoms: remainingAtoms,
95592
- relations,
95593
- types: []
95594
- });
95595
- this.setDataInstance(newInstance);
95665
+ this.dataInstance.removeAtom(atomId);
95596
95666
  console.log(`\u2705 Atom removed from data instance: ${atomToDelete.label} (${atomToDelete.id})`);
95597
- await this.enforceConstraintsAndRegenerate();
95598
95667
  console.log(`\u{1F389} Atom deletion completed: ${atomToDelete.label} (${atomToDelete.id})`);
95599
95668
  this.dispatchEvent(new CustomEvent("atom-deleted", {
95600
95669
  detail: { atom: atomToDelete }
@@ -95634,9 +95703,7 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
95634
95703
  console.log(`\u{1F5D1}\uFE0F Found tuple in relation "${relationId}": ${targetTuple.atoms.join(" \u2192 ")}`);
95635
95704
  this.dataInstance.removeRelationTuple(relationId, targetTuple);
95636
95705
  console.log(`\u2705 Relation tuple removed from data instance: ${relationId}: ${targetTuple.atoms.join(" \u2192 ")}`);
95637
- await this.enforceConstraintsAndRegenerate();
95638
95706
  console.log(`\u{1F389} Relation tuple deletion completed: ${relationId}: ${targetTuple.atoms.join(" \u2192 ")}`);
95639
- this.updateDeletionSelects();
95640
95707
  this.dispatchEvent(new CustomEvent("relation-tuple-deleted", {
95641
95708
  detail: { relationId, tuple: targetTuple }
95642
95709
  }));
@@ -95672,6 +95739,19 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
95672
95739
  getDataInstance() {
95673
95740
  return this.dataInstance;
95674
95741
  }
95742
+ /**
95743
+ * Get the current constraint error (if any)
95744
+ * Returns null if all constraints are currently satisfied
95745
+ */
95746
+ getCurrentConstraintError() {
95747
+ return this.currentConstraintError;
95748
+ }
95749
+ /**
95750
+ * Check if there are currently unsatisfied constraints
95751
+ */
95752
+ hasConstraintErrors() {
95753
+ return this.currentConstraintError !== null;
95754
+ }
95675
95755
  /**
95676
95756
  * Set the CnD specification
95677
95757
  */