Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@ckeditor/ckeditor5-autoformat

Package Overview
Dependencies
Maintainers
1
Versions
713
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ckeditor/ckeditor5-autoformat - npm Package Compare versions

Comparing version 19.0.1 to 20.0.0

28

package.json
{
"name": "@ckeditor/ckeditor5-autoformat",
"version": "19.0.1",
"version": "20.0.0",
"description": "Autoformatting feature for CKEditor 5.",

@@ -13,19 +13,19 @@ "keywords": [

"dependencies": {
"@ckeditor/ckeditor5-core": "^19.0.1",
"@ckeditor/ckeditor5-typing": "^19.0.1"
"@ckeditor/ckeditor5-core": "^20.0.0",
"@ckeditor/ckeditor5-typing": "^20.0.0"
},
"devDependencies": {
"@ckeditor/ckeditor5-basic-styles": "^19.0.1",
"@ckeditor/ckeditor5-block-quote": "^19.0.1",
"@ckeditor/ckeditor5-code-block": "^19.0.1",
"@ckeditor/ckeditor5-editor-classic": "^19.0.1",
"@ckeditor/ckeditor5-engine": "^19.0.1",
"@ckeditor/ckeditor5-enter": "^19.0.1",
"@ckeditor/ckeditor5-heading": "^19.0.1",
"@ckeditor/ckeditor5-list": "^19.0.1",
"@ckeditor/ckeditor5-paragraph": "^19.1.0",
"@ckeditor/ckeditor5-undo": "^19.0.1"
"@ckeditor/ckeditor5-basic-styles": "^20.0.0",
"@ckeditor/ckeditor5-block-quote": "^20.0.0",
"@ckeditor/ckeditor5-code-block": "^20.0.0",
"@ckeditor/ckeditor5-editor-classic": "^20.0.0",
"@ckeditor/ckeditor5-engine": "^20.0.0",
"@ckeditor/ckeditor5-enter": "^20.0.0",
"@ckeditor/ckeditor5-heading": "^20.0.0",
"@ckeditor/ckeditor5-list": "^20.0.0",
"@ckeditor/ckeditor5-paragraph": "^20.0.0",
"@ckeditor/ckeditor5-undo": "^20.0.0"
},
"engines": {
"node": ">=8.0.0",
"node": ">=12.0.0",
"npm": ">=5.7.1"

@@ -32,0 +32,0 @@ },

@@ -10,4 +10,4 @@ /**

import BlockAutoformatEditing from './blockautoformatediting';
import InlineAutoformatEditing from './inlineautoformatediting';
import blockAutoformatEditing from './blockautoformatediting';
import inlineAutoformatEditing from './inlineautoformatediting';
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';

@@ -55,9 +55,7 @@

if ( commands.get( 'bulletedList' ) ) {
// eslint-disable-next-line no-new
new BlockAutoformatEditing( this.editor, /^[*-]\s$/, 'bulletedList' );
blockAutoformatEditing( this.editor, this, /^[*-]\s$/, 'bulletedList' );
}
if ( commands.get( 'numberedList' ) ) {
// eslint-disable-next-line no-new
new BlockAutoformatEditing( this.editor, /^1[.|)]\s$/, 'numberedList' );
blockAutoformatEditing( this.editor, this, /^1[.|)]\s$/, 'numberedList' );
}

@@ -85,12 +83,9 @@ }

if ( commands.get( 'bold' ) ) {
/* eslint-disable no-new */
const boldCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'bold' );
new InlineAutoformatEditing( this.editor, /(\*\*)([^*]+)(\*\*)$/g, boldCallback );
new InlineAutoformatEditing( this.editor, /(__)([^_]+)(__)$/g, boldCallback );
/* eslint-enable no-new */
inlineAutoformatEditing( this.editor, this, /(\*\*)([^*]+)(\*\*)$/g, boldCallback );
inlineAutoformatEditing( this.editor, this, /(__)([^_]+)(__)$/g, boldCallback );
}
if ( commands.get( 'italic' ) ) {
/* eslint-disable no-new */
const italicCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'italic' );

@@ -100,21 +95,16 @@

// text before the pattern (e.g. `(?:^|[^\*])`).
new InlineAutoformatEditing( this.editor, /(?:^|[^*])(\*)([^*_]+)(\*)$/g, italicCallback );
new InlineAutoformatEditing( this.editor, /(?:^|[^_])(_)([^_]+)(_)$/g, italicCallback );
/* eslint-enable no-new */
inlineAutoformatEditing( this.editor, this, /(?:^|[^*])(\*)([^*_]+)(\*)$/g, italicCallback );
inlineAutoformatEditing( this.editor, this, /(?:^|[^_])(_)([^_]+)(_)$/g, italicCallback );
}
if ( commands.get( 'code' ) ) {
/* eslint-disable no-new */
const codeCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'code' );
new InlineAutoformatEditing( this.editor, /(`)([^`]+)(`)$/g, codeCallback );
/* eslint-enable no-new */
inlineAutoformatEditing( this.editor, this, /(`)([^`]+)(`)$/g, codeCallback );
}
if ( commands.get( 'strikethrough' ) ) {
/* eslint-disable no-new */
const strikethroughCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'strikethrough' );
new InlineAutoformatEditing( this.editor, /(~~)([^~]+)(~~)$/g, strikethroughCallback );
/* eslint-enable no-new */
inlineAutoformatEditing( this.editor, this, /(~~)([^~]+)(~~)$/g, strikethroughCallback );
}

@@ -144,4 +134,3 @@ }

// eslint-disable-next-line no-new
new BlockAutoformatEditing( this.editor, pattern, () => {
blockAutoformatEditing( this.editor, this, pattern, () => {
if ( !command.isEnabled ) {

@@ -167,4 +156,3 @@ return false;

if ( this.editor.commands.get( 'blockQuote' ) ) {
// eslint-disable-next-line no-new
new BlockAutoformatEditing( this.editor, /^>\s$/, 'blockQuote' );
blockAutoformatEditing( this.editor, this, /^>\s$/, 'blockQuote' );
}

@@ -183,4 +171,3 @@ }

if ( this.editor.commands.get( 'codeBlock' ) ) {
// eslint-disable-next-line no-new
new BlockAutoformatEditing( this.editor, /^```$/, 'codeBlock' );
blockAutoformatEditing( this.editor, this, /^```$/, 'codeBlock' );
}

@@ -190,3 +177,3 @@ }

// Helper function for getting `InlineAutoformatEditing` callbacks that checks if command is enabled.
// Helper function for getting `inlineAutoformatEditing` callbacks that checks if command is enabled.
//

@@ -193,0 +180,0 @@ // @param {module:core/editor/editor~Editor} editor

@@ -5,7 +5,2 @@ /**

*/
/**
* @module autoformat/blockautoformatediting
*/
import LiveRange from '@ckeditor/ckeditor5-engine/src/model/liverange';

@@ -20,106 +15,102 @@

*
* See the constructors documentation to learn how to create custom inline autoformatters. You can also use
* See the {@link module:autoformat/blockautoformatediting~blockAutoformatEditing `blockAutoformatEditing`} documentation
* to learn how to create custom block autoformatters. You can also use
* the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters
* (lists, headings, bold and italic).
*
* @module autoformat/blockautoformatediting
*/
export default class BlockAutoformatEditing {
/**
* @inheritDoc
*/
static get pluginName() {
return 'BlockAutoformatEditing';
}
/**
* Creates a listener triggered on `change` event in the document.
* Calls the callback when inserted text matches the regular expression or the command name
* if provided instead of the callback.
*
* Examples of usage:
*
* To convert a paragraph to heading 1 when `- ` is typed, using just the command name:
*
* new BlockAutoformatEditing( editor, /^\- $/, 'heading1' );
*
* To convert a paragraph to heading 1 when `- ` is typed, using just the callback:
*
* new BlockAutoformatEditing( editor, /^\- $/, ( context ) => {
* const { match } = context;
* const headingLevel = match[ 1 ].length;
*
* editor.execute( 'heading', {
* formatId: `heading${ headingLevel }`
* } );
* } );
*
* @param {module:core/editor/editor~Editor} editor The editor instance.
* @param {RegExp} pattern The regular expression to execute on just inserted text.
* @param {Function|String} callbackOrCommand The callback to execute or the command to run when the text is matched.
* In case of providing the callback, it receives the following parameter:
* * {Object} match RegExp.exec() result of matching the pattern to inserted text.
*/
constructor( editor, pattern, callbackOrCommand ) {
let callback;
let command = null;
/**
* Creates a listener triggered on {@link module:engine/model/document~Document#event:change:data `change:data`} event in the document.
* Calls the callback when inserted text matches the regular expression or the command name
* if provided instead of the callback.
*
* Examples of usage:
*
* To convert a paragraph to heading 1 when `- ` is typed, using just the command name:
*
* blockAutoformatEditing( editor, plugin, /^\- $/, 'heading1' );
*
* To convert a paragraph to heading 1 when `- ` is typed, using just the callback:
*
* blockAutoformatEditing( editor, plugin, /^\- $/, ( context ) => {
* const { match } = context;
* const headingLevel = match[ 1 ].length;
*
* editor.execute( 'heading', {
* formatId: `heading${ headingLevel }`
* } );
* } );
*
* @param {module:core/editor/editor~Editor} editor The editor instance.
* @param {module:autoformat/autoformat~Autoformat} plugin The autoformat plugin instance.
* @param {RegExp} pattern The regular expression to execute on just inserted text.
* @param {Function|String} callbackOrCommand The callback to execute or the command to run when the text is matched.
* In case of providing the callback, it receives the following parameter:
* * {Object} match RegExp.exec() result of matching the pattern to inserted text.
*/
export default function blockAutoformatEditing( editor, plugin, pattern, callbackOrCommand ) {
let callback;
let command = null;
if ( typeof callbackOrCommand == 'function' ) {
callback = callbackOrCommand;
} else {
// We assume that the actual command name was provided.
command = editor.commands.get( callbackOrCommand );
if ( typeof callbackOrCommand == 'function' ) {
callback = callbackOrCommand;
} else {
// We assume that the actual command name was provided.
command = editor.commands.get( callbackOrCommand );
callback = () => {
editor.execute( callbackOrCommand );
};
callback = () => {
editor.execute( callbackOrCommand );
};
}
editor.model.document.on( 'change:data', ( evt, batch ) => {
if ( command && !command.isEnabled || !plugin.isEnabled ) {
return;
}
editor.model.document.on( 'change', ( evt, batch ) => {
if ( command && !command.isEnabled ) {
return;
}
if ( batch.type == 'transparent' ) {
return;
}
if ( batch.type == 'transparent' ) {
return;
}
const changes = Array.from( editor.model.document.differ.getChanges() );
const entry = changes[ 0 ];
const changes = Array.from( editor.model.document.differ.getChanges() );
const entry = changes[ 0 ];
// Typing is represented by only a single change.
if ( changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1 ) {
return;
}
// Typing is represented by only a single change.
if ( changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1 ) {
return;
}
const blockToFormat = entry.position.parent;
const blockToFormat = entry.position.parent;
// Block formatting should trigger only if the entire content of a paragraph is a single text node... (see ckeditor5#5671).
if ( !blockToFormat.is( 'paragraph' ) || blockToFormat.childCount !== 1 ) {
return;
}
// Block formatting should trigger only if the entire content of a paragraph is a single text node... (see ckeditor5#5671).
if ( !blockToFormat.is( 'paragraph' ) || blockToFormat.childCount !== 1 ) {
return;
}
const match = pattern.exec( blockToFormat.getChild( 0 ).data );
const match = pattern.exec( blockToFormat.getChild( 0 ).data );
// ...and this text node's data match the pattern.
if ( !match ) {
return;
}
// ...and this text node's data match the pattern.
if ( !match ) {
return;
}
// Use enqueueChange to create new batch to separate typing batch from the auto-format changes.
editor.model.enqueueChange( writer => {
// Matched range.
const start = writer.createPositionAt( blockToFormat, 0 );
const end = writer.createPositionAt( blockToFormat, match[ 0 ].length );
const range = new LiveRange( start, end );
// Use enqueueChange to create new batch to separate typing batch from the auto-format changes.
editor.model.enqueueChange( writer => {
// Matched range.
const start = writer.createPositionAt( blockToFormat, 0 );
const end = writer.createPositionAt( blockToFormat, match[ 0 ].length );
const range = new LiveRange( start, end );
const wasChanged = callback( { match } );
const wasChanged = callback( { match } );
// Remove matched text.
if ( wasChanged !== false ) {
writer.remove( range );
}
// Remove matched text.
if ( wasChanged !== false ) {
writer.remove( range );
}
range.detach();
} );
range.detach();
} );
}
} );
}

@@ -7,8 +7,2 @@ /**

/**
* @module autoformat/inlineautoformatediting
*/
import getLastTextLine from '@ckeditor/ckeditor5-typing/src/utils/getlasttextline';
/**
* The inline autoformatting engine. It allows to format various inline patterns. For example,

@@ -20,195 +14,167 @@ * it can be configured to make "foo" bold when typed `**foo**` (the `**` markers will be removed).

*
* See the constructors documentation to learn how to create custom inline autoformatters. You can also use
* See the {@link module:autoformat/inlineautoformatediting~inlineAutoformatEditing `inlineAutoformatEditing`} documentation
* to learn how to create custom inline autoformatters. You can also use
* the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters
* (lists, headings, bold and italic).
*
* @module autoformat/inlineautoformatediting
*/
export default class InlineAutoformatEditing {
/**
* @inheritDoc
*/
static get pluginName() {
return 'InlineAutoformatEditing';
}
/**
* Enables autoformatting mechanism for a given {@link module:core/editor/editor~Editor}.
*
* It formats the matched text by applying the given model attribute or by running the provided formatting callback.
* On every change applied to the model the autoformatting engine checks the text on the left of the selection
* and executes the provided action if the text matches given criteria (regular expression or callback).
*
* @param {module:core/editor/editor~Editor} editor The editor instance.
* @param {Function|RegExp} testRegexpOrCallback The regular expression or callback to execute on text.
* Provided regular expression *must* have three capture groups. The first and the third capture group
* should match opening and closing delimiters. The second capture group should match the text to format.
*
* // Matches the `**bold text**` pattern.
* // There are three capturing groups:
* // - The first to match the starting `**` delimiter.
* // - The second to match the text to format.
* // - The third to match the ending `**` delimiter.
* new InlineAutoformatEditing( editor, /(\*\*)([^\*]+?)(\*\*)$/g, 'bold' );
*
* When a function is provided instead of the regular expression, it will be executed with the text to match as a parameter.
* The function should return proper "ranges" to delete and format.
*
* {
* remove: [
* [ 0, 1 ], // Remove the first letter from the given text.
* [ 5, 6 ] // Remove the 6th letter from the given text.
* ],
* format: [
* [ 1, 5 ] // Format all letters from 2nd to 5th.
* ]
* }
*
* @param {Function|String} attributeOrCallback The name of attribute to apply on matching text or a callback for manual
* formatting. If callback is passed it should return `false` if changes should not be applied (e.g. if a command is disabled).
*
* // Use attribute name:
* new InlineAutoformatEditing( editor, /(\*\*)([^\*]+?)(\*\*)$/g, 'bold' );
*
* // Use formatting callback:
* new InlineAutoformatEditing( editor, /(\*\*)([^\*]+?)(\*\*)$/g, ( writer, rangesToFormat ) => {
* const command = editor.commands.get( 'bold' );
*
* if ( !command.isEnabled ) {
* return false;
* }
*
* const validRanges = editor.model.schema.getValidRanges( rangesToFormat, 'bold' );
*
* for ( let range of validRanges ) {
* writer.setAttribute( 'bold', true, range );
* }
* } );
*/
constructor( editor, testRegexpOrCallback, attributeOrCallback ) {
let regExp;
let attributeKey;
let testCallback;
let formatCallback;
/**
* Enables autoformatting mechanism for a given {@link module:core/editor/editor~Editor}.
*
* It formats the matched text by applying the given model attribute or by running the provided formatting callback.
* On every {@link module:engine/model/document~Document#event:change:data data change} in the model document
* the autoformatting engine checks the text on the left of the selection
* and executes the provided action if the text matches given criteria (regular expression or callback).
*
* @param {module:core/editor/editor~Editor} editor The editor instance.
* @param {module:autoformat/autoformat~Autoformat} plugin The autoformat plugin instance.
* @param {Function|RegExp} testRegexpOrCallback The regular expression or callback to execute on text.
* Provided regular expression *must* have three capture groups. The first and the third capture group
* should match opening and closing delimiters. The second capture group should match the text to format.
*
* // Matches the `**bold text**` pattern.
* // There are three capturing groups:
* // - The first to match the starting `**` delimiter.
* // - The second to match the text to format.
* // - The third to match the ending `**` delimiter.
* inlineAutoformatEditing( editor, plugin, /(\*\*)([^\*]+?)(\*\*)$/g, formatCallback );
*
* When a function is provided instead of the regular expression, it will be executed with the text to match as a parameter.
* The function should return proper "ranges" to delete and format.
*
* {
* remove: [
* [ 0, 1 ], // Remove the first letter from the given text.
* [ 5, 6 ] // Remove the 6th letter from the given text.
* ],
* format: [
* [ 1, 5 ] // Format all letters from 2nd to 5th.
* ]
* }
*
* @param {Function} formatCallback A callback to apply actual formatting.
* It should return `false` if changes should not be applied (e.g. if a command is disabled).
*
* inlineAutoformatEditing( editor, plugin, /(\*\*)([^\*]+?)(\*\*)$/g, ( writer, rangesToFormat ) => {
* const command = editor.commands.get( 'bold' );
*
* if ( !command.isEnabled ) {
* return false;
* }
*
* const validRanges = editor.model.schema.getValidRanges( rangesToFormat, 'bold' );
*
* for ( let range of validRanges ) {
* writer.setAttribute( 'bold', true, range );
* }
* } );
*/
export default function inlineAutoformatEditing( editor, plugin, testRegexpOrCallback, formatCallback ) {
let regExp;
let testCallback;
if ( testRegexpOrCallback instanceof RegExp ) {
regExp = testRegexpOrCallback;
} else {
testCallback = testRegexpOrCallback;
}
if ( testRegexpOrCallback instanceof RegExp ) {
regExp = testRegexpOrCallback;
} else {
testCallback = testRegexpOrCallback;
}
if ( typeof attributeOrCallback == 'string' ) {
attributeKey = attributeOrCallback;
} else {
formatCallback = attributeOrCallback;
}
// A test callback run on changed text.
testCallback = testCallback || ( text => {
let result;
const remove = [];
const format = [];
// A test callback run on changed text.
testCallback = testCallback || ( text => {
let result;
const remove = [];
const format = [];
while ( ( result = regExp.exec( text ) ) !== null ) {
// There should be full match and 3 capture groups.
if ( result && result.length < 4 ) {
break;
}
while ( ( result = regExp.exec( text ) ) !== null ) {
// There should be full match and 3 capture groups.
if ( result && result.length < 4 ) {
break;
}
let {
index,
'1': leftDel,
'2': content,
'3': rightDel
} = result;
let {
index,
'1': leftDel,
'2': content,
'3': rightDel
} = result;
// Real matched string - there might be some non-capturing groups so we need to recalculate starting index.
const found = leftDel + content + rightDel;
index += result[ 0 ].length - found.length;
// Real matched string - there might be some non-capturing groups so we need to recalculate starting index.
const found = leftDel + content + rightDel;
index += result[ 0 ].length - found.length;
// Start and End offsets of delimiters to remove.
const delStart = [
index,
index + leftDel.length
];
const delEnd = [
index + leftDel.length + content.length,
index + leftDel.length + content.length + rightDel.length
];
// Start and End offsets of delimiters to remove.
const delStart = [
index,
index + leftDel.length
];
const delEnd = [
index + leftDel.length + content.length,
index + leftDel.length + content.length + rightDel.length
];
remove.push( delStart );
remove.push( delEnd );
remove.push( delStart );
remove.push( delEnd );
format.push( [ index + leftDel.length, index + leftDel.length + content.length ] );
}
format.push( [ index + leftDel.length, index + leftDel.length + content.length ] );
}
return {
remove,
format
};
} );
return {
remove,
format
};
} );
editor.model.document.on( 'change:data', ( evt, batch ) => {
if ( batch.type == 'transparent' || !plugin.isEnabled ) {
return;
}
// A format callback run on matched text.
formatCallback = formatCallback || ( ( writer, rangesToFormat ) => {
const validRanges = editor.model.schema.getValidRanges( rangesToFormat, attributeKey );
const model = editor.model;
const selection = model.document.selection;
for ( const range of validRanges ) {
writer.setAttribute( attributeKey, true, range );
}
// Do nothing if selection is not collapsed.
if ( !selection.isCollapsed ) {
return;
}
// After applying attribute to the text, remove given attribute from the selection.
// This way user is able to type a text without attribute used by auto formatter.
writer.removeSelectionAttribute( attributeKey );
} );
const changes = Array.from( model.document.differ.getChanges() );
const entry = changes[ 0 ];
editor.model.document.on( 'change', ( evt, batch ) => {
if ( batch.type == 'transparent' ) {
return;
}
// Typing is represented by only a single change.
if ( changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1 ) {
return;
}
const model = editor.model;
const selection = model.document.selection;
const focus = selection.focus;
const block = focus.parent;
const { text, range } = getTextAfterCode( model.createRange( model.createPositionAt( block, 0 ), focus ), model );
const testOutput = testCallback( text );
const rangesToFormat = testOutputToRanges( range.start, testOutput.format, model );
const rangesToRemove = testOutputToRanges( range.start, testOutput.remove, model );
// Do nothing if selection is not collapsed.
if ( !selection.isCollapsed ) {
return;
}
if ( !( rangesToFormat.length && rangesToRemove.length ) ) {
return;
}
const changes = Array.from( model.document.differ.getChanges() );
const entry = changes[ 0 ];
// Use enqueueChange to create new batch to separate typing batch from the auto-format changes.
model.enqueueChange( writer => {
// Apply format.
const hasChanged = formatCallback( writer, rangesToFormat );
// Typing is represented by only a single change.
if ( changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1 ) {
// Strict check on `false` to have backward compatibility (when callbacks were returning `undefined`).
if ( hasChanged === false ) {
return;
}
const focus = selection.focus;
const block = focus.parent;
const { text, range } = getLastTextLine( model.createRange( model.createPositionAt( block, 0 ), focus ), model );
const testOutput = testCallback( text );
const rangesToFormat = testOutputToRanges( range.start, testOutput.format, model );
const rangesToRemove = testOutputToRanges( range.start, testOutput.remove, model );
if ( !( rangesToFormat.length && rangesToRemove.length ) ) {
return;
// Remove delimiters - use reversed order to not mix the offsets while removing.
for ( const range of rangesToRemove.reverse() ) {
writer.remove( range );
}
// Use enqueueChange to create new batch to separate typing batch from the auto-format changes.
model.enqueueChange( writer => {
// Apply format.
const hasChanged = formatCallback( writer, rangesToFormat );
// Strict check on `false` to have backward compatibility (when callbacks were returning `undefined`).
if ( hasChanged === false ) {
return;
}
// Remove delimiters - use reversed order to not mix the offsets while removing.
for ( const range of rangesToRemove.reverse() ) {
writer.remove( range );
}
} );
} );
}
} );
}
// Converts output of the test function provided to the InlineAutoformatEditing and converts it to the model ranges
// Converts output of the test function provided to the inlineAutoformatEditing and converts it to the model ranges
// inside provided block.

@@ -227,1 +193,25 @@ //

}
// Returns the last text line after the last code element from the given range.
// It is similar to {@link module:typing/utils/getlasttextline.getLastTextLine `getLastTextLine()`},
// but it ignores any text before the last `code`.
//
// @param {module:engine/model/range~Range} range
// @param {module:engine/model/model~Model} model
// @returns {module:typing/utils/getlasttextline~LastTextLineData}
function getTextAfterCode( range, model ) {
let start = range.start;
const text = Array.from( range.getItems() ).reduce( ( rangeText, node ) => {
// Trim text to a last occurrence of an inline element and update range start.
if ( !( node.is( 'text' ) || node.is( 'textProxy' ) ) || node.getAttribute( 'code' ) ) {
start = model.createPositionAfter( node );
return '';
}
return rangeText + node.data;
}, '' );
return { text, range: model.createRange( start, range.end ) };
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc