Файловый менеджер - Редактировать - /var/www/html/mediawiki-1.43.1/extensions/VisualEditor/lib/ve/tests/dm/ve.dm.TreeModifier.test.js
Ðазад
/*! * VisualEditor DataModel TreeModifier tests. * * @copyright See AUTHORS.txt */ ve.dm.TreeModifier.prototype.dump = function () { const lines = [], del = this.deletions, ins = this.insertions; function nodeTag( idx, node ) { return ( idx === undefined ? '' : idx + ' ' ) + ( del.includes( node ) ? 'DEL ' : ins.includes( node ) ? 'INS ' : '' ); } function appendNodeLines( indent, node, idx ) { const sp = '-\t'.repeat( indent ); if ( node.type === 'text' ) { lines.push( sp + nodeTag( idx, node ) + 'VeDmTextNode(' + node.getOuterLength() + ')' ); return; } lines.push( sp + nodeTag( idx, node ) + node.constructor.name + '(' + node.getOuterLength() + ')' ); if ( node.hasChildren() ) { node.children.forEach( ( child, i ) => { appendNodeLines( indent + 1, child, i ); } ); } } appendNodeLines( 0, this.document.documentNode ); lines.push( 'inserter: { path: [ ' + this.inserter.path.join( ', ' ) + ' ], offset: ' + this.inserter.offset + ' }, ' + 'linear ' + this.inserter.linearOffset + ', insertions: ' + JSON.stringify( this.insertedPositions ) ); lines.push( 'remover: { path: [ ' + this.remover.path.join( ', ' ) + ' ], offset: ' + this.remover.offset + ' }, ' + 'linear ' + this.remover.linearOffset ); lines.push( 'insertedPositions: ' + JSON.stringify( this.insertedPositions ) ); lines.push( 'insertedNodes: ' + JSON.stringify( this.insertedNodes ) ); lines.push( 'adjustments: ' + JSON.stringify( this.adjustmentTree ) ); lines.push( 'adjusted inserter: ' + JSON.stringify( this.adjustInserterPosition( this.getRawInserterPosition() ) ) ); lines.push( 'adjusted remover: ' + JSON.stringify( this.adjustRemoverPosition( this.getRawRemoverPosition( { path: this.remover.path, offset: this.remover.offset, node: this.remover.node } ) ) ) ); ve.batchSplice( lines, lines.length, 0, this.data.data.map( ( item, i ) => i + ':' + JSON.stringify( item ) + ',' ) ); return lines.join( '\n' ); }; ve.test.utils.nodesByTypeSummary = function ( doc ) { const nodesByType = ve.copy( doc.nodesByType ); for ( const type in nodesByType ) { nodesByType[ type ] = nodesByType[ type ].length; } return nodesByType; }; QUnit.module( 've.dm.TreeModifier' ); QUnit.test( 'treeDiff', ( assert ) => { // old: <div><p>foobarbaz</p><p>qux</p></div><p>quux</p> // new: <ul><li><p>foo</p><p>barBAZ</p><p>qux</p></li></ul><p>qUUx</p><p><img src='x'></p> // tx: {-<div>-|+<ul><li>+}<p>foo{+</p><p>+}bar{-baz-|+BAZ+}</p><p>qux</p>{-</div>-|+</li></ul>+}<p>q{-uu-|+UU+}x</p>{+<p><img src='x'></p>+} const origData = [ { type: 'div' }, { type: 'paragraph' }, ...'foobarbaz', { type: '/paragraph' }, { type: 'paragraph' }, ...'qux', { type: '/paragraph' }, { type: '/div' }, { type: 'paragraph' }, ...'quux', { type: '/paragraph' } ]; const tx = new ve.dm.Transaction( [ { type: 'replace', remove: [ { type: 'div' } ], insert: [ { type: 'list' }, { type: 'listItem' } ] }, { type: 'retain', length: 4 }, { type: 'replace', remove: [], insert: [ { type: '/paragraph' }, { type: 'paragraph' } ] }, { type: 'retain', length: 3 }, { type: 'replace', remove: [ ...'baz' ], insert: [ ...'baz' ] }, { type: 'retain', length: 6 }, { type: 'replace', remove: [ { type: '/div' } ], insert: [ { type: '/listItem' }, { type: '/list' } ] }, { type: 'retain', length: 2 }, { type: 'replace', remove: [ ...'uu' ], insert: [ ...'UU' ] }, { type: 'retain', length: 2 }, { type: 'replace', remove: [], insert: [ { type: 'paragraph' }, { type: 'inlineImage', attributes: { src: 'x' } }, { type: '/inlineImage' }, { type: '/paragraph' } ] } ] ); const treeDiff = [ // {-<div>-|+<ul><li>+} [ { type: 'insertNode', isContent: false, at: [ 0 ], element: { type: 'list' } }, // { 0: { diff: 1 } } { type: 'insertNode', isContent: false, at: [ 0, 0 ], element: { type: 'listItem' } } ], // Retain 4 [ { type: 'insertNode', isContent: false, at: [ 0, 0, 0 ], element: { type: 'paragraph' } }, { type: 'moveText', isContent: true, from: [ 1, 0, 0 ], to: [ 0, 0, 0, 0 ], length: 3 } // { 0: { diff: 1 }, 1: { 0: { 0: { diff: -3 } } } } ], // {+</p><p>+} [ { type: 'insertNode', isContent: false, at: [ 0, 0, 1 ], element: { type: 'paragraph' } } ], // Retain 3 [ { type: 'moveText', isContent: true, from: [ 1, 0, 0 ], length: 3, to: [ 0, 0, 1, 0 ] } // { 0: { diff: 1 }, 1: { 0: { 0: { diff: -6 } } } } ], // {-baz-|+BAZ+} [ { type: 'removeText', isContent: true, at: [ 1, 0, 0 ], data: [ ...'baz' ] }, // { 0: { diff: 1 }, 1: { 0: { 0: { diff: -9 } } } } { type: 'insertText', isContent: true, at: [ 0, 0, 1, 3 ], data: [ ...'baz' ] } ], // Retain 6 [ { type: 'removeNode', isContent: false, at: [ 1, 0 ], element: { type: 'paragraph' } }, // { 0: { diff: 1 }, 1: { 0: { diff: -1 } } } { type: 'moveNode', isContent: false, from: [ 1, 0 ], to: [ 0, 0, 2 ] } // { 0: { diff: 1 }, 1: { 0: { diff: -2 } } } ], // {-</div>-|+</li></ul>+} [ { type: 'removeNode', isContent: false, at: [ 1 ], element: { type: 'div' } } // { 0: { diff: 1 }, 1: { diff: -1 } } ], // Retain 2 [], // {-uu-|+UU+} [ { type: 'removeText', isContent: true, at: [ 1, 1 ], data: [ ...'uu' ] }, // NOT THIS: { 0: { diff: 1 }, 1: { diff: -1 }, 2: { 1: { diff: -2 } } } // { 0: { diff: 1 }, 1: { 1: { diff: -2 }, diff: -1 } } { type: 'insertText', isContent: true, at: [ 1, 1 ], data: [ ...'UU' ] } // { 0: { diff: 1 }, 1: { diff: -1 }, 2: { 1: { diff: 0 } } } ], // Retain 2 [], // {+<p><img src='x'></p>+} [ { type: 'insertNode', isContent: false, at: [ 2 ], element: { type: 'paragraph' } }, { type: 'insertNode', isContent: true, at: [ 2, 0 ], element: { type: 'inlineImage', attributes: { src: 'x' } } } ], // Implicit final retain [] ]; const surface = new ve.dm.Surface( ve.dm.example.createExampleDocumentFromData( origData ) ); const doc = surface.documentModel; ve.dm.treeModifier.setup( doc ); let j = 0; for ( let i = 0, iLen = tx.operations.length; i < iLen; i++ ) { ve.dm.treeModifier.processLinearOperation( tx.operations[ i ] ); assert.deepEqual( ve.dm.treeModifier.treeOps.slice( j ), treeDiff[ i ], 'Linear operation ' + i + ': induced tree operations' ); j = ve.dm.treeModifier.treeOps.length; } ve.dm.treeModifier.processImplicitFinalRetain(); assert.deepEqual( ve.dm.treeModifier.treeOps.slice( j ), treeDiff[ treeDiff.length - 1 ], 'Implicit final retain: induced tree operations' ); } ); QUnit.test( 'modify', ( assert ) => { function dumpTree( d ) { // Build a tree modifier just for the .dump method (don't modify anything) const treeModifier = new ve.dm.TreeModifier(); treeModifier.setup( d ); return treeModifier.dump(); } const origData = [ { type: 'paragraph' }, ...'abcd', { type: '/paragraph' }, { type: 'paragraph' }, ...'efg', { type: '/paragraph' }, { type: 'paragraph' }, ...'hij', { type: '/paragraph' }, { type: 'internalList' }, { type: '/internalList' } ]; const surface = new ve.dm.Surface( ve.dm.example.createExampleDocumentFromData( origData ) ); const doc = surface.documentModel; const tx = new ve.dm.Transaction( [ { type: 'retain', length: 2 }, { type: 'replace', remove: [ 'b' ], insert: [ ...'xy' ], insertedDataOffset: 0, insertedDataLength: 2 }, { type: 'retain', length: 2 }, { type: 'replace', remove: [ { type: '/paragraph' }, { type: 'paragraph' }, 'e' ], insert: [ 'Z' ], insertedDataOffset: 0, insertedDataLength: 0 }, { type: 'retain', length: 4 }, { type: 'replace', remove: [ 'h' ], insert: [ { type: 'inlineImage' }, { type: '/inlineImage' } ], insertedDataOffset: 0, insertedDataLength: 2 }, { type: 'retain', length: 3 } ] ); assert.deepEqual( ve.test.utils.nodesByTypeSummary( doc ), { document: 1, internalList: 1, paragraph: 3, text: 3 }, 'Nodes by type before' ); doc.commit( tx ); let actualTreeDump = dumpTree( doc ); doc.rebuildTree(); let expectedTreeDump = dumpTree( doc ); assert.strictEqual( actualTreeDump, expectedTreeDump, 'Modified tree matches rebuilt tree, forward' ); assert.deepEqual( ve.test.utils.nodesByTypeSummary( doc ), { document: 1, inlineImage: 1, internalList: 1, paragraph: 2, text: 2 }, 'Nodes by type after transaction' ); doc.commit( tx.reversed() ); actualTreeDump = dumpTree( doc ); doc.rebuildTree(); expectedTreeDump = dumpTree( doc ); assert.strictEqual( actualTreeDump, expectedTreeDump, 'Modified tree matches rebuilt tree, reversed' ); assert.notStrictEqual( tx.operations[ 3 ].remove[ 1 ], doc.data.data[ 6 ], 'Inserted transaction data is not referenced into the linear data' ); assert.deepEqual( ve.test.utils.nodesByTypeSummary( doc ), { document: 1, internalList: 1, paragraph: 3, text: 3 }, 'Nodes by type after undo' ); } ); QUnit.test( 'bare content', ( assert ) => { const data = [ { type: 'paragraph' }, ...'Foo', { type: '/paragraph' } ]; const doc = ve.dm.example.createExampleDocumentFromData( data ); const tx = new ve.dm.Transaction( [ { type: 'replace', remove: [ { type: 'paragraph' } ], insert: [] }, { type: 'retain', length: 3 }, { type: 'replace', remove: [ { type: '/paragraph' } ], insert: [] } ] ); assert.throws( () => { doc.commit( tx ); }, /Error: Cannot insert text into a document node/, 'bare content' ); } ); QUnit.test( 'unbalanced insertion', ( assert ) => { const data = [ { type: 'div' }, { type: '/div' } ]; const doc = ve.dm.example.createExampleDocumentFromData( data ); const tx = new ve.dm.Transaction( [ { type: 'retain', length: 1 }, { type: 'replace', remove: [], insert: [ { type: 'paragraph' }, { type: '/heading' } ] }, { type: 'retain', length: 1 } ] ); assert.throws( () => { doc.commit( tx ); }, /Expected closing for paragraph but got closing for heading/, 'unbalanced insertion' ); } ); QUnit.test( 'applyTreeOperation: ensureNotText', ( assert ) => { const data = [ { type: 'paragraph' }, ...'fo', { type: 'inlineImage' }, { type: '/inlineImage' }, 'o', { type: '/paragraph' } ]; const expectData = ve.copy( data ); expectData[ 3 ].annotations = [ ve.dm.example.boldHash ]; const doc = ve.dm.example.createExampleDocumentFromData( data ); const tx = new ve.dm.Transaction( [ { type: 'retain', length: 3 }, { type: 'replace', remove: [ { type: 'inlineImage' }, { type: '/inlineImage' } ], insert: [ { type: 'inlineImage', annotations: [ ve.dm.example.boldHash ] }, { type: '/inlineImage' } ] }, { type: 'retain', length: 2 } ] ); assert.deepEqual( ve.test.utils.nodesByTypeSummary( doc ), { document: 1, inlineImage: 1, paragraph: 1, text: 2 }, 'Nodes by type before' ); doc.commit( tx ); assert.deepEqual( doc.data.data, expectData, 'Bold inline element surrounded by text' ); assert.deepEqual( ve.test.utils.nodesByTypeSummary( doc ), { document: 1, inlineImage: 1, paragraph: 1, text: 2 }, 'Nodes by type after' ); } ); QUnit.test( 'setupBlockSlugs', ( assert ) => { const doc = new ve.dm.Surface( ve.dm.example.createExampleDocumentFromData( [] ) ).documentModel; assert.deepEqual( ve.test.utils.nodesByTypeSummary( doc ), { document: 1 }, 'Nodes by type before' ); doc.commit( new ve.dm.Transaction( [ { type: 'replace', remove: [], insert: [ { type: 'paragraph' }, { type: '/paragraph' } ], insertedDataOffset: 0, insertedDataLength: 2 } ] ) ); assert.deepEqual( doc.getDocumentNode().getChildren()[ 0 ].slugPositions, { 0: true }, 'Modified paragraph node contains a slug' ); assert.deepEqual( ve.test.utils.nodesByTypeSummary( doc ), { document: 1, paragraph: 1 }, 'Nodes by type before' ); } ); QUnit.test( 'checkEqualData', ( assert ) => { const data = [ { type: 'paragraph', originalDomElementsHash: 'h1111111111111111', internal: { changesSinceLoad: 1 } }, ...'foo', { type: 'mwReference', attributes: { mw: { name: 'ref', attrs: {}, body: { id: 'mw-reference-text-cite_note-1' } }, listIndex: 0, listGroup: 'mwReference/', listKey: 'auto/0', refGroup: '', contentsUsed: true, refListItemId: 'mw-reference-text-cite_note-1' } }, { type: '/mwReference' }, { type: '/paragraph' } ]; const expectedData = ve.copy( data ); expectedData[ 0 ].originalDomElementsHash = 'h2222222222222222'; expectedData[ 0 ].internal.changesSinceLoad = 2; delete expectedData[ 4 ].attributes.mw; delete expectedData[ 4 ].attributes.contentsUsed; ve.dm.TreeModifier.static.checkEqualData( data, expectedData ); assert.true( true, 'Normalized data compares equal' ); } ); QUnit.test( 'TreeCursor#crossIgnoredNodes', ( assert ) => { const data = [ { type: 'paragraph' }, ...'foo', { type: 'comment', attributes: { text: 'de' } }, { type: '/comment' }, { type: '/paragraph' } ]; const doc = ve.dm.example.createExampleDocumentFromData( data ); const tx = new ve.dm.Transaction( [ { type: 'retain', length: 3 }, { type: 'replace', remove: [ 'o', { type: 'comment', attributes: { text: 'de' } }, { type: '/comment' } ], insert: [] }, { type: 'retain', length: 1 } ] ); assert.deepEqual( ve.test.utils.nodesByTypeSummary( doc ), { comment: 1, document: 1, paragraph: 1, text: 1 }, 'Nodes by type before' ); doc.commit( tx ); assert.deepEqual( doc.data.data, [].concat( data.slice( 0, 3 ), data.slice( 6 ) ), 'Can remove an inline node after a text node' ); assert.deepEqual( ve.test.utils.nodesByTypeSummary( doc ), { document: 1, paragraph: 1, text: 1 }, 'Nodes by type after' ); } ); QUnit.test( 'TreeCursor#normalizeCursor', ( assert ) => { const data = [ { type: 'heading', attributes: { level: 1 } }, ...'ab', { type: 'comment', attributes: { text: 'foo' } }, { type: '/comment' }, 'd', { type: '/heading' }, { type: 'paragraph' }, ...'ef', { type: '/paragraph' } ]; const doc = ve.dm.example.createExampleDocumentFromData( data ); const tx = new ve.dm.Transaction( [ { type: 'retain', length: 2 }, { type: 'replace', remove: [ 'b', { type: 'comment', attributes: { text: 'foo' } }, { type: '/comment' }, 'd' ], insert: [] }, { type: 'retain', length: 2 }, { type: 'replace', remove: [ 'e' ], insert: [] }, { type: 'retain', length: 1 } ] ); assert.deepEqual( ve.test.utils.nodesByTypeSummary( doc ), { comment: 1, document: 1, heading: 1, paragraph: 1, text: 3 }, 'Nodes by type before' ); doc.commit( tx ); assert.deepEqual( doc.data.data, [].concat( data.slice( 0, 2 ), data.slice( 6, 8 ), data.slice( 9 ) ), 'Ignore removed nodes properly when normalizing from a text node' ); assert.deepEqual( ve.test.utils.nodesByTypeSummary( doc ), { document: 1, heading: 1, paragraph: 1, text: 2 }, 'Nodes by type after' ); } );
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка