Răsfoiți Sursa

Improved util functions.

Maciej Bukowski 6 ani în urmă
părinte
comite
174911a2e7

+ 47 - 6
packages/ckeditor5-watchdog/src/utils/areconnectedThroughProperties.js

@@ -12,16 +12,18 @@ import getSubNodes from './getsubnodes';
 /**
 /**
  * Traverses both structures to find out whether there is a reference that is shared between both structures.
  * Traverses both structures to find out whether there is a reference that is shared between both structures.
  *
  *
- * @param {Object|Array} obj1
- * @param {Object|Array} obj2
+ * @param {Object|Array} target1
+ * @param {Object|Array} target2
  */
  */
-export default function areConnectedThroughProperties( obj1, obj2, excludedProperties = new Set() ) {
-	if ( obj1 === obj2 && isObject( obj1 ) ) {
+export default function areConnectedThroughProperties( target1, target2, excludedNodes = new Set() ) {
+	if ( target1 === target2 && isObject( target1 ) ) {
 		return true;
 		return true;
 	}
 	}
 
 
-	const subNodes1 = getSubNodes( obj1, excludedProperties );
-	const subNodes2 = getSubNodes( obj2, excludedProperties );
+	// @if CK_DEBUG_WATCHDOG // return checkConnectionBetweenProps( target1, target2, excludedNodes );
+
+	const subNodes1 = getSubNodes( target1, excludedNodes );
+	const subNodes2 = getSubNodes( target2, excludedNodes );
 
 
 	for ( const node of subNodes1 ) {
 	for ( const node of subNodes1 ) {
 		if ( subNodes2.has( node ) ) {
 		if ( subNodes2.has( node ) ) {
@@ -32,6 +34,45 @@ export default function areConnectedThroughProperties( obj1, obj2, excludedPrope
 	return false;
 	return false;
 }
 }
 
 
+/* istanbul ignore next */
+// eslint-disable-next-line
+function checkConnectionBetweenProps( target1, target2, excludedNodes ) {
+	const { subNodes: subNodes1, prevNodeMap: prevNodeMap1 } = getSubNodes( target1, excludedNodes.subNodes );
+	const { subNodes: subNodes2, prevNodeMap: prevNodeMap2 } = getSubNodes( target2, excludedNodes.subNodes );
+
+	for ( const sharedNode of subNodes1 ) {
+		if ( subNodes2.has( sharedNode ) ) {
+			const connection = [];
+
+			connection.push( sharedNode );
+
+			let node = prevNodeMap1.get( sharedNode );
+
+			while ( node && node !== target1 ) {
+				connection.push( node );
+				node = prevNodeMap1.get( node );
+			}
+
+			node = prevNodeMap2.get( sharedNode );
+
+			while ( node && node !== target2 ) {
+				connection.unshift( node );
+				node = prevNodeMap2.get( node );
+			}
+
+			console.log( '--------' );
+			console.log( { target1 } );
+			console.log( { sharedNode } );
+			console.log( { target2 } );
+			console.log( { connection } );
+
+			return true;
+		}
+	}
+
+	return false;
+}
+
 function isObject( structure ) {
 function isObject( structure ) {
 	return typeof structure === 'object' && structure !== null;
 	return typeof structure === 'object' && structure !== null;
 }
 }

+ 34 - 7
packages/ckeditor5-watchdog/src/utils/getsubnodes.js

@@ -12,6 +12,8 @@
 export default function getSubNodes( head, excludedProperties = new Set() ) {
 export default function getSubNodes( head, excludedProperties = new Set() ) {
 	const nodes = [ head ];
 	const nodes = [ head ];
 
 
+	// @if CK_DEBUG_WATCHDOG // const prevNodeMap = new Map();
+
 	// Nodes are stored to prevent infinite looping.
 	// Nodes are stored to prevent infinite looping.
 	const subNodes = new Set();
 	const subNodes = new Set();
 
 
@@ -28,29 +30,54 @@ export default function getSubNodes( head, excludedProperties = new Set() ) {
 		if ( node[ Symbol.iterator ] ) {
 		if ( node[ Symbol.iterator ] ) {
 			// The custom editor iterators might cause some problems if the editor is crashed.
 			// The custom editor iterators might cause some problems if the editor is crashed.
 			try {
 			try {
-				nodes.push( ...node );
+				for ( const n of node ) {
+					nodes.push( n );
+
+					// @if CK_DEBUG_WATCHDOG // if ( !prevNodeMap.has( node[ key ] ) ) {
+					// @if CK_DEBUG_WATCHDOG // 	prevNodeMap.set( n, node );
+					// @if CK_DEBUG_WATCHDOG // }
+				}
 			} catch ( err ) {
 			} catch ( err ) {
+				// Do not log errors for broken structures
+				// since we are in the error handling process already.
 				// eslint-disable-line no-empty
 				// eslint-disable-line no-empty
 			}
 			}
 		} else {
 		} else {
-			nodes.push( ...Object.values( node ) );
+			for ( const key in node ) {
+				// We share references (objects) in the ProtobufFactory within the editors,
+				// hence the whole object should be skipped. Although, it's not a perfect
+				// solution since new places like that might occur in the future.
+				if ( key === 'nested' ) {
+					continue;
+				}
+
+				nodes.push( node[ key ] );
+
+				// @if CK_DEBUG_WATCHDOG // if ( !prevNodeMap.has( node[ key ] ) ) {
+				// @if CK_DEBUG_WATCHDOG // 	prevNodeMap.set( n, node );
+				// @if CK_DEBUG_WATCHDOG // }
+			}
 		}
 		}
 	}
 	}
 
 
+	// @if CK_DEBUG_WATCHDOG // return { subNodes, prevNodeMap };
+
 	return subNodes;
 	return subNodes;
 }
 }
 
 
 function shouldNodeBeSkipped( node ) {
 function shouldNodeBeSkipped( node ) {
 	const type = Object.prototype.toString.call( node );
 	const type = Object.prototype.toString.call( node );
+	const typeOfNode = typeof node;
 
 
 	return (
 	return (
-		type === '[object Number]' ||
-		type === '[object Boolean]' ||
-		type === '[object String]' ||
-		type === '[object Symbol]' ||
-		type === '[object Function]' ||
+		typeOfNode === 'number' ||
+		typeOfNode === 'boolean' ||
+		typeOfNode === 'string' ||
+		typeOfNode === 'symbol' ||
+		typeOfNode === 'function' ||
 		type === '[object Date]' ||
 		type === '[object Date]' ||
 		type === '[object RegExp]' ||
 		type === '[object RegExp]' ||
+		type === '[object Module]' ||
 
 
 		node === undefined ||
 		node === undefined ||
 		node === null ||
 		node === null ||