New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

text-machine

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

text-machine - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

doc/config.md

9

.eslintrc.js

@@ -9,3 +9,3 @@ module.exports = {

'parserOptions': {
'ecmaVersion': 8
'ecmaVersion': 2020
} ,

@@ -30,5 +30,6 @@ 'extends': [ 'eslint:recommended' ] ,

'no-lonely-if': 'error' ,
'no-nested-ternary': 'error' ,
'no-nested-ternary': 'off' , // Now I use the streamlined ternary operator a lot
'no-shadow': 'warn' ,
'no-shadow-restricted-names': 'error' ,
'require-atomic-updates': 'off' , // check for possible race condition on assignment, interesting but too nitpicky

@@ -64,2 +65,3 @@

'MemberExpression': 1 ,
'flatTernaryExpressions': true
} ] ,

@@ -134,4 +136,5 @@ 'newline-per-chained-call': [ 'error', {

'ObjectPattern' : {
// object destructuring assigment
'consistent': true ,
'minProperties': 6
'minProperties': 8
}

@@ -138,0 +141,0 @@ } ] ,

/*
Text Machine
Copyright (c) 2018 Cédric Ronvel
Copyright (c) 2018 - 2022 Cédric Ronvel

@@ -43,6 +43,8 @@ The MIT License (MIT)

this.index = 0 ;
// TODO
//this.offset = 0 ;
//this.savedStateStack = [] ;
this.sanitize() ;
this.reset() ;

@@ -55,8 +57,24 @@ }

TextMachine.prototype.reset = function reset() {
this.stateStack = [ {
name: this.program.config.initState || 'init'
} ] ;
const MATCH_ALWAYS = 0 ;
const MATCH_STRING = 1 ;
const MATCH_SET = 2 ;
const MATCH_REGEXP = 3 ;
const MATCH_FUNCTION = 4 ;
//this.offset = 0 ;
TextMachine.prototype.sanitize = function() {
if ( this.program.states && typeof this.program.states === 'object' ) {
for ( let name in this.program.states ) {
let stateProgram = this.program.states[ name ] ;
if ( stateProgram.branches ) {
for ( let branchProgram of stateProgram.branches ) { this.sanitizeBranchProgram( branchProgram ) ; }
}
if ( stateProgram.bufferBranches ) {
for ( let branchProgram of stateProgram.bufferBranches ) { this.sanitizeBranchProgram( branchProgram ) ; }
}
}
}
} ;

@@ -66,154 +84,270 @@

TextMachine.prototype.pushEvent = function pushEvent( event , context ) {
var currentState , bufferProgram , stateProgram , eventProgram ,
delayedAction , stateHasSwitched = false , oldState , primaryContext , startingContext , actionBuffer , errorAction ;
TextMachine.prototype.sanitizeBranchProgram = function( branchProgram ) {
if ( branchProgram.match === true ) {
branchProgram.matchType = MATCH_ALWAYS ;
}
else if ( typeof branchProgram.match === 'string' ) {
branchProgram.matchType = MATCH_STRING ;
}
else if ( Array.isArray( branchProgram.match ) ) {
branchProgram.match = new Set( branchProgram.match ) ;
branchProgram.matchType = MATCH_SET ;
}
else if ( branchProgram.match instanceof Set ) {
branchProgram.matchType = MATCH_SET ;
}
else if ( branchProgram.match instanceof RegExp ) {
branchProgram.matchType = MATCH_REGEXP ;
}
else if ( typeof branchProgram.match === 'function' ) {
branchProgram.matchType = MATCH_FUNCTION ;
}
} ;
// Get the current state
currentState = this.stateStack[ this.stateStack.length - 1 ] ;
// Active state program
stateProgram = this.program.states[ currentState.name ] ;
delayedAction = false ;
TextMachine.prototype.reset = function() {
this.index = 0 ;
for ( ;; ) {
eventProgram = this.eventProgramMatch( stateProgram.events , event ) ;
this.stateStack = [ {
name: this.program.config.initState || 'init' ,
parent: null ,
microState: {} ,
span: {}
} ] ;
} ;
if ( ! eventProgram ) { break ; }
primaryContext = currentState.context ;
startingContext = currentState.startingContext ;
errorAction = undefined ;
actionBuffer = undefined ;
// Check for state switching
if (
( eventProgram.state && eventProgram.state !== currentState.name ) ||
( eventProgram.return && this.stateStack.length > 1 )
) {
stateHasSwitched = true ;
TextMachine.prototype.pushEvent = function( event , context ) {
var initialState , state ,
initialStateProgram , stateProgram , branchProgram , bufferBranchProgram ,
//delayedAction , buffer ,
isDelayed = false ,
stateHasSwitched = false ;
bufferProgram = this.eventProgramMatch( stateProgram.buffer , currentState.buffer ) ;
//console.error( "\n>>> PUSH: '" + event + "'" ) ;
// Get the current state
initialState = state = this.stateStack[ this.stateStack.length - 1 ] ;
if ( bufferProgram ) {
actionBuffer = currentState.buffer ;
eventProgram = Object.assign( {} , eventProgram , bufferProgram ) ;
}
// Active state program
initialStateProgram = stateProgram = this.program.states[ state.name ] ;
if ( eventProgram.delay ) {
delayedAction = stateProgram.action ;
}
do {
// First we select the branch and apply its feats
oldState = currentState ;
branchProgram = this.branchMatch( state , stateProgram.branches , event ) ;
// Update to the new state
if ( eventProgram.return && this.stateStack.length > 1 ) {
this.stateStack.pop() ;
currentState = this.stateStack[ this.stateStack.length - 1 ] ;
stateProgram = this.program.states[ currentState.name ] ;
startingContext = currentState.enteringContext ;
if ( branchProgram ) {
// Buffer branches are only matched on state-changes
if ( branchProgram.state && branchProgram.state !== state.name ) {
bufferBranchProgram = this.branchMatch( state , stateProgram.bufferBranches , state.buffer ) ;
if ( typeof eventProgram.return === 'string' && eventProgram.return !== currentState.enteringState ) {
// We are returning from an unexpected subProgram
if ( eventProgram.errorAction ) { errorAction = eventProgram.errorAction ; }
// A buffer-branch has matched, it replace the current branch-program
if ( bufferBranchProgram ) {
branchProgram = bufferBranchProgram ;
}
}
else {
if ( eventProgram.return ) {
// We are in a state where we cannot return
if ( eventProgram.errorAction ) { errorAction = eventProgram.errorAction ; }
if ( branchProgram.microState ) {
for ( let name in branchProgram.microState ) {
if ( branchProgram.microState[ name ] ) { state.microState[ name ] = true ; }
else { delete state.microState[ name ] ; }
}
}
stateProgram = this.program.states[ eventProgram.state ] ;
if ( branchProgram.delay ) { isDelayed = true ; }
if ( stateProgram.subProgram ) {
// Save the entering context
currentState.enteringContext = context ;
currentState.enteringState = eventProgram.state ;
// Exec the branch action on the current state now, if any...
if ( branchProgram.return && branchProgram.returnErrorAction && (
this.stateStack.length <= 1
|| ( typeof branchProgram.return === 'string' && branchProgram.return !== state.openingState )
) ) {
// This is a return error (mostly parenthesis/brace/bracket parse errors)
//console.error( ">>> APPLY branch returnErrorAction" ) ;
this.execActions( branchProgram.returnErrorAction , state , context ) ;
}
else if ( branchProgram.action ) {
this.execActions( branchProgram.action , state , context ) ;
}
}
// Create and push a new state
currentState = {
name: eventProgram.state ,
context: context
} ;
this.stateStack.push( currentState ) ;
}
else {
// Overwrite the old state with the new one
currentState = this.stateStack[ this.stateStack.length - 1 ] = {
name: eventProgram.state ,
previousName: currentState.name ,
context: context ,
previousContext: currentState.context
} ;
}
// Now it depends on which branching mode occured
currentState.startingContext = eventProgram.continue ? oldState.startingContext : context ;
if ( this.stateStack.length > 1 && ( stateProgram.returnAfter || branchProgram?.return ) ) {
// Returning from sub-state (recursion)
//console.error( "RETURN" , state.name , '-->' , state.openingState , '(wanted: ' + ( stateProgram.returnAfter || branchProgram?.return ) + ')' , '-->-->' , state.parent?.returnState ) ;
if ( stateProgram.buffer ) {
currentState.buffer = eventProgram.preserveBuffer ? oldState.buffer + event : event ;
}
stateHasSwitched = true ;
this.stateStack.length -- ;
state = this.stateStack[ this.stateStack.length - 1 ] ;
stateProgram = this.program.states[ state.name ] ;
if ( state.returnState ) {
// Overwrite the old state with the new one
stateProgram = this.program.states[ state.returnState ] ;
state = this.stateStack[ this.stateStack.length - 1 ] = {
name: state.returnState ,
parent: state.parent ,
context: context ,
previousName: state.name ,
previousContext: state.context ,
microState: state.microState ,
span: state.span ,
openingContext: state.openingContext ,
openingState: state.openingState ,
startingStateContext: context ,
buffer:
! stateProgram.bufferBranches ? null :
branchProgram.preserveBuffer ? state.buffer + event :
event
} ;
}
}
else {
currentState.previousName = currentState.name ;
currentState.previousContext = currentState.context ;
currentState.context = context ;
else if ( ! branchProgram || (
( ! branchProgram.state || branchProgram.state === state.name )
&& ! branchProgram.subState
&& ( ! branchProgram.return || this.stateStack.length <= 1 )
) ) {
// Continue / No state change
//console.error( "CONTINUE" , state.name ) ;
if ( stateProgram.buffer ) {
currentState.buffer += event ;
state.previousName = state.name ;
state.previousContext = state.context ;
state.context = context ;
if ( stateProgram.bufferBranches ) {
state.buffer += event ;
}
}
else if ( branchProgram.subState ) {
// Entering sub-state (recursion)
//console.error( "ENTERING SUB STATE" , state.name , '-->' , branchProgram.subState ) ;
// Exec the switching state action now, if any...
if ( errorAction ) {
this.execAction( errorAction , primaryContext , startingContext , actionBuffer ) ;
stateHasSwitched = true ;
stateProgram = this.program.states[ branchProgram.subState ] ;
// Save the opening context
state.returnState = branchProgram.state ;
// Create a new state and push it at the end of the stack
state = this.stateStack[ this.stateStack.length ] = {
name: branchProgram.subState ,
parent: state ,
context: context ,
microState: {} ,
span: {} ,
openingContext: context ,
openingState: branchProgram.subState ,
startingStateContext: context
} ;
}
else if ( eventProgram.action ) {
this.execAction( eventProgram.action , primaryContext , startingContext , actionBuffer ) ;
else {
// Switch to state
//console.error( "SWITCH" , state.name , '-->' , branchProgram.state ) ;
stateHasSwitched = true ;
// Now change the state
stateProgram = this.program.states[ branchProgram.state ] ;
state = this.stateStack[ this.stateStack.length - 1 ] = {
name: branchProgram.state ,
parent: state.parent ,
context: context ,
previousName: state.name ,
previousContext: state.context ,
microState: state.microState ,
span: state.span ,
openingContext: state.openingContext ,
openingState: state.openingState ,
startingStateContext: context ,
buffer:
! stateProgram.bufferBranches ? null :
branchProgram.preserveBuffer ? state.buffer + event :
event
} ;
}
// Propagate now?
if ( ! stateHasSwitched || ! eventProgram.propagate ) { break ; }
}
// Finally apply state feats
// Exec the finishing state action, if any...
if ( delayedAction !== false ) { this.execAction( delayedAction , context ) ; }
else if ( stateProgram.action ) { this.execAction( stateProgram.action , context ) ; }
} ;
if ( stateProgram.span ) {
let span = state.span[ stateProgram.span ] ;
if ( span && span.end === this.index - 1 ) {
span.end = this.index ;
span.endingContext = context ;
}
else {
span = state.span[ stateProgram.span ] = {
startingContext: context ,
endingContext: context ,
start: this.index ,
end: this.index
} ;
}
}
if ( stateProgram.microState ) {
for ( let name in stateProgram.microState ) {
if ( stateProgram.microState[ name ] ) { state.microState[ name ] = true ; }
else { delete state.microState[ name ] ; }
}
}
// Get the first matching eventProgram
TextMachine.prototype.eventProgramMatch = function eventProgramMatch( eventPrograms , event ) {
if ( ! Array.isArray( eventPrograms ) ) { return ; }
// Exec the action for the state, if any...
if ( isDelayed ) {
if ( initialStateProgram.action ) {
this.execActions( initialStateProgram.action , initialState , context ) ;
}
}
else if ( stateProgram.returnAfter && stateProgram.returnErrorAction && (
this.stateStack.length <= 1
|| ( typeof stateProgram.returnAfter === 'string' && stateProgram.returnAfter !== state.openingState )
) ) {
// This is a return error (mostly parenthesis/brace/bracket parse errors)
//console.error( ">>> APPLY state returnErrorAction" , this.stateStack.length , stateProgram.returnAfter , state.openingState ) ;
this.execActions( stateProgram.returnErrorAction , state , context ) ;
}
else if ( stateProgram.action ) {
this.execActions( stateProgram.action , state , context ) ;
}
var eventProgram , match , isPositive ,
i , iMax = eventPrograms.length ;
// Propagate the event to the next state now?
} while ( stateHasSwitched && branchProgram?.propagate ) ;
for ( i = 0 ; i < iMax ; i ++ ) {
eventProgram = eventPrograms[ i ] ;
isPositive = eventProgram.match !== undefined || eventProgram.dontMatch === undefined ;
match = eventProgram.match || eventProgram.dontMatch ;
this.index ++ ;
} ;
if (
// Always match
match === isPositive ||
// Equality
( typeof match === 'string' && ( match === event ) === isPositive ) ||
// Included in an array of string
( Array.isArray( match ) && match.includes( event ) === isPositive ) ||
// Get the first matching branchProgram
TextMachine.prototype.branchMatch = function( state , branches , event ) {
if ( ! Array.isArray( branches ) ) { return ; }
// Match a RegExp
( match instanceof RegExp && match.test( event ) === isPositive ) ||
for ( let branchProgram of branches ) {
let isMatching =
branchProgram.matchType === MATCH_ALWAYS ? true :
branchProgram.matchType === MATCH_STRING ? branchProgram.match === event :
branchProgram.matchType === MATCH_SET ? branchProgram.match.has( event ) :
branchProgram.matchType === MATCH_REGEXP ? branchProgram.match.test( event ) :
branchProgram.matchType === MATCH_FUNCTION ? !! branchProgram.match( event ) :
false ;
// Third party function
( typeof match === 'function' && !! match( event ) === isPositive )
) {
return eventProgram ;
if ( isMatching === ! branchProgram.inverse ) {
if ( ! branchProgram.hasMicroState ) { return branchProgram ; }
if (
Array.isArray( branchProgram.hasMicroState )
&& branchProgram.hasMicroState.every( name => state.microState[ name ] )
) {
return branchProgram ;
}
if ( state.microState[ branchProgram.hasMicroState ] ) {
return branchProgram ;
}
}

@@ -225,21 +359,48 @@ }

TextMachine.prototype.execAction = function execAction( action , context , startingContext , buffer ) {
if ( Array.isArray( action[ 0 ] ) ) {
// This is an array of array, it contains many actions to execute
action.forEach( action_ => this.execAction( action_ , context , startingContext , buffer ) ) ;
return ;
TextMachine.prototype.execActions = function( actions , state , context ) {
if ( ! actions || ! actions.length ) { return ; }
if ( ! Array.isArray( actions[ 0 ] ) ) {
return this.execAction( actions , state , context ) ;
}
if ( this.api[ action[ 0 ] ] ) {
context.startingContext = startingContext ;
context.buffer = buffer ;
for ( let action of actions ) {
this.execAction( action , state , context ) ;
}
} ;
if ( ! Array.isArray( action[ 1 ] ) ) {
// Pack action's argument once
action[ 1 ] = action.slice( 1 ) ;
TextMachine.prototype.execAction = function( action , state , context ) {
var actionName = action[ 0 ] ;
//console.error( "ACTION:" , actionName ) ;
switch ( actionName ) {
case 'style' :
this.api.style( context , action[ 1 ] ) ;
break ;
case 'starterStyle' :
//console.error( " -> " , state.startingStateContext.x , state.startingStateContext.y ) ;
this.api.style( state.startingStateContext , action[ 1 ] ) ;
break ;
case 'openerStyle' :
//console.error( " -> " , state.openingContext.x , state.openingContext.y ) ;
this.api.style( state.openingContext , action[ 1 ] ) ;
break ;
case 'streakStyle' :
this.api.blockStyle( state.startingStateContext , context , action[ 1 ] ) ;
break ;
case 'spanStyle' : {
let span = state.span[ action[ 1 ] ] ;
//console.error( " -> " , span ) ;
if ( ! span ) { break ; }
this.api.blockStyle( span.startingContext , span.endingContext , action[ 2 ] ) ;
break ;
}
this.api[ action[ 0 ] ]( context , ... action[ 1 ] ) ;
case 'hint' :
// /!\ Should be refactored...
this.api.hint( context , state.buffer , action[ 1 ] ) ;
break ;
}
} ;
{
"name": "text-machine",
"version": "0.1.0",
"version": "0.2.0",
"description": "A state machine for text processing.",
"main": "lib/TextMachine.js",
"engines": {
"node": ">=6.0.0"
"node": ">=14.15.0"
},

@@ -34,6 +34,7 @@ "directories": {

"years": [
2018
2018,
2022
],
"owner": "Cédric Ronvel"
}
}
}
/*
Text Machine
Copyright (c) 2015 Cédric Ronvel
Copyright (c) 2018 - 2022 Cédric Ronvel

@@ -35,39 +35,73 @@ The MIT License (MIT)

var idleStyle = { color: 'white' } ;
var keywordStyle = { color: 'brightWhite' , bold: true } ;
var thisStyle = { color: 'brightRed' , bold: true } ;
var constantKeywordStyle = { color: 'brightBlue' , bold: true } ;
var constantStyle = { color: 'brightBlue' } ;
var identifierStyle = { color: 'red' } ;
var numberStyle = { color: 'cyan' } ;
var stringStyle = { color: 'blue' } ;
var escapeStyle = { color: 'brightCyan' , bold: true } ;
var commentStyle = { color: 'brightBlack' } ;
var propertyStyle = { color: 'green' } ;
var methodStyle = { color: 'brightYellow' } ;
var coreMethodStyle = { color: 'brightYellow' , bold: true } ;
var classStyle = { color: 'magenta' } ;
var coreClassOrObjectStyle = { color: 'brightMagenta' , bold: true } ;
const idleStyle = { color: 'white' } ;
const keywordStyle = { color: 'brightWhite' , bold: true } ;
const operatorStyle = { color: 'brightWhite' , bold: true } ;
const assignmentStyle = { color: 'brightWhite' , bold: true } ;
const thisStyle = { color: 'brightRed' , bold: true } ;
const constantKeywordStyle = { color: 'brightBlue' , bold: true } ;
const constantStyle = { color: 'brightBlue' } ;
const identifierStyle = { color: 'red' } ;
const numberStyle = { color: 'cyan' } ;
const stringStyle = { color: 'blue' } ;
const escapeStyle = { color: 'brightCyan' , bold: true } ;
const templatePlaceholderStyle = { color: 'brightCyan' , bold: true } ;
const commentStyle = { color: 'brightBlack' } ;
const propertyStyle = { color: 'green' } ;
const methodStyle = { color: 'brightYellow' } ;
const coreMethodStyle = { color: 'brightYellow' , bold: true } ;
const classStyle = { color: 'magenta' } ;
const coreClassOrObjectStyle = { color: 'brightMagenta' , bold: true } ;
var parseErrorStyle = { color: 'brightWhite' , bgColor: 'red' , bold: true } ;
var braceStyle = { color: 'brightWhite' , bold: true } ;
const regexpStyle = { color: 'blue' } ;
const regexpDelemiterStyle = { color: 'brightMagenta' , bold: true } ;
const regexpParenthesisStyle = { color: 'yellow' , bold: true } ;
const regexpBracketStyle = { color: 'brightMagenta' , bold: true } ;
const regexpAlternativeStyle = { color: 'yellow' , bold: true } ;
const regexpMarkupStyle = { color: 'brightMagenta' } ;
const regexpClassStyle = { color: 'magenta' } ;
const regexpFlagStyle = { color: 'brightCyan' } ;
const parseErrorStyle = { color: 'brightWhite' , bgColor: 'red' , bold: true } ;
const braceStyle = { color: 'brightWhite' , bold: true } ;
var keywords = [
'do' , 'if' , 'in' , 'for' , 'let' , 'new' , 'try' , 'var' , 'case' , 'else' , 'enum' ,
'eval' , 'void' , 'with' , 'await' , 'break' , 'catch' , 'class' , 'const' ,
'super' , 'throw' , 'while' , 'yield' , 'delete' , 'export' , 'import' , 'public' , 'return' ,
'static' , 'switch' , 'typeof' , 'default' , 'extends' , 'finally' , 'package' , 'private' ,
'continue' , 'debugger' , 'function' , 'arguments' , 'interface' , 'protected' , 'implements' , 'instanceof' ,
// Node pseudo keywords
'exports' , 'global' , 'module' , 'require' , '__filename' , '__dirname'
const keywords = [
'var' , 'let' , 'const' ,
'do' , 'while' , 'for' , 'in' , 'of' , 'switch' , 'case' , 'default' , 'break' , 'continue' ,
'if' , 'else' ,
'function' , 'arguments' , 'async' , 'await' , 'return' , 'yield' ,
'throw' , 'try' , 'catch' , 'finally' ,
'new' , 'class' , 'extends' , 'static' , 'public' , 'protected' , 'private' , 'implements' , 'interface' , 'super' ,
'typeof' , 'instanceof' ,
'delete' ,
'enum' , 'eval' , 'void' , 'with' ,
'export' , 'import' , 'package' ,
'debugger' ,
] ;
var constantKeywords = [
'true' , 'false' , 'null' , 'undefined' , 'Infinity' , 'NaN'
const operators = [
'+' , '++' , '-' , '--' , '*' , '**' , '%' , // '/'
'&&' , '||' , '!' , '!!' ,
'==' , '===' , '!=' , '!==' , '<' , '<=' , '>' , '>=' ,
'&' , '|' , '^' , '<<' , '>>' , '>>>' ,
'??'
] ;
var coreMethods = [
const assignments = [
'=' ,
'+=' , '-=' , '*=' , '%=' , // '/='
'&=' , '|=' , '^='
] ;
const constantKeywords = [
'true' , 'false' , 'null' , 'undefined' , 'Infinity' , 'NaN' ,
// Node pseudo-constant
'__filename' , '__dirname'
] ;
const coreMethods = [
'setTimeout' , 'clearTimeout' , 'setInterval' , 'clearInterval' , 'setImmediate' , 'clearImmediate' ,

@@ -77,6 +111,6 @@ 'isNaN' , 'isFinite' , 'parseInt' , 'parseFloat' ,

// Node
'unref' , 'ref'
'unref' , 'ref' , 'require'
] ;
var coreClassesOrObjects = [
const coreClassesOrObjects = [
'Array' , 'Boolean' , 'Date' , 'Error' , 'Function' , 'Intl' , 'Math' , 'Number' , 'Object' , 'String' , 'RegExp' ,

@@ -91,2 +125,3 @@ 'EvalError' , 'RangeError' , 'ReferenceError' , 'SyntaxError' , 'TypeError' ,

// Node
'exports' , 'global' , 'module' ,
'process' , 'Buffer' ,

@@ -98,3 +133,3 @@

var memberKeywords = [
const specialMember = [
'prototype' , 'constructor'

@@ -105,3 +140,3 @@ ] ;

var coreMethodHints = {
const coreMethodHints = {
setTimeout: 'timerID = setTimeout( callback , ms )' ,

@@ -118,3 +153,3 @@ clearTimeout: 'clearTimeout( timerID )' ,

var prog = {
const prog = {
hostConfig: { // Accessible by the host

@@ -125,17 +160,15 @@ } ,

} ,
states: { // Every states of the machine
states: {
idle: {
action: [ 'style' , idleStyle ] , // action when this state is active at the end of the event
buffer: false , // if an array, this state start buffering as long as it last
//checkpoint: true , // true if the past will not have influence on the future anymore: help optimizing the host
events: [
action: [ 'style' , idleStyle ] ,
branches: [
{
match: /^[a-zA-Z_$]/ , // the event should match this to trigger those actions
state: 'identifier' , // next state
propagate: false , // eat the event or propagate it immediately to the next state?
action: null , // action at trigger time, run before the action of the next state
delay: false // for this time, the old state action will be executed rather than the new one
match: /^[a-zA-Z_$]/ ,
state: 'identifier'
} ,
{
match: /^[=.<>^?!&|~*%+-]/ ,
state: 'operator'
} ,
{
match: /^[0-9]/ ,

@@ -145,2 +178,6 @@ state: 'number'

{
match: "'" ,
state: 'singleQuoteString'
} ,
{
match: '"' ,

@@ -150,4 +187,4 @@ state: 'doubleQuoteString'

{
match: "'" ,
state: 'singleQuoteString'
match: '`' ,
state: 'templateString'
} ,

@@ -160,3 +197,3 @@ {

match: '{' ,
state: 'openBrace'
subState: 'openBrace'
} ,

@@ -169,3 +206,3 @@ {

match: '[' ,
state: 'openBracket'
subState: 'openBracket'
} ,

@@ -178,3 +215,3 @@ {

match: '(' ,
state: 'openParenthesis'
subState: 'openParenthesis'
} ,

@@ -184,8 +221,47 @@ {

state: 'closeParenthesis'
} ,
{
match: ':' ,
state: 'colon' ,
}
]
} ,
// In the middle of an expression, after any constant/value/identifier/function call/etc...
// Mostly like idle, except that slash can be divide sign instead of RegExp
idleAfterValue: {
action: [ 'style' , idleStyle ] , // action when this state is active at the end of the event
branches: [
{
match: '/' ,
state: 'idleAfterValueSlash'
} ,
{
match: ' ' ,
state: 'idleAfterValue'
} ,
{
match: true ,
state: 'idle' ,
propagate: true
}
]
} ,
number: {
action: [ 'style' , numberStyle ] ,
branches: [
{
match: /^[0-9.]/ ,
state: 'number'
} ,
{
match: true ,
state: 'idleAfterValue' ,
propagate: true
}
]
} ,
identifier: {
action: [ 'style' , identifierStyle ] ,
events: [
span: 'identifier' ,
branches: [
{

@@ -199,59 +275,133 @@ match: /^[a-zA-Z0-9_$]/ ,

propagate: true ,
continue: true // Keep the starting context
}
] ,
// Buffers are checked on state switching
buffer: [
bufferBranches: [
{
match: 'this' ,
// replace the 'action' of the event, also work with any properties of the event except 'match' BTW
action: [ 'blockStyle' , thisStyle ] ,
state: 'afterIdentifier'
//propagate: true ,
//continue: true
action: [ 'spanStyle' , 'identifier' , thisStyle ] ,
state: 'afterIdentifier' ,
propagate: true
} ,
{
match: keywords ,
action: [ 'blockStyle' , keywordStyle ] ,
state: 'idle'
action: [ 'spanStyle' , 'identifier' , keywordStyle ] ,
state: 'idle' ,
propagate: true
} ,
{
match: constantKeywords ,
action: [ 'blockStyle' , constantKeywordStyle ] ,
state: 'idle'
action: [ 'spanStyle' , 'identifier' , constantKeywordStyle ] ,
state: 'idleAfterValue' ,
propagate: true
} ,
{
match: coreMethods ,
action: [ [ 'blockStyle' , coreMethodStyle ] , [ 'hint' , coreMethodHints ] ] ,
state: 'idle'
action: [ [ 'spanStyle' , 'identifier' , coreMethodStyle ] , [ 'hint' , coreMethodHints ] ] ,
state: 'idle' ,
propagate: true
} ,
{
match: coreClassesOrObjects ,
action: [ 'blockStyle' , coreClassOrObjectStyle ] ,
action: [ 'spanStyle' , 'identifier' , coreClassOrObjectStyle ] ,
state: 'afterIdentifier' ,
propagate: true ,
continue: true
propagate: true
} ,
{
match: /^[A-Z][A-Z0-9_]+$/ ,
action: [ 'blockStyle' , constantStyle ] ,
action: [ 'spanStyle' , 'identifier' , constantStyle ] ,
state: 'afterIdentifier' ,
propagate: true ,
continue: true
propagate: true
} ,
{
match: /^[A-Z]/ ,
action: [ 'blockStyle' , classStyle ] ,
action: [ 'spanStyle' , 'identifier' , classStyle ] ,
state: 'afterIdentifier' ,
propagate: true
}
]
} ,
afterIdentifier: {
action: [ 'style' , idleStyle ] ,
branches: [
{
match: ' ' ,
state: 'afterIdentifier'
} ,
{
match: '.' ,
state: 'dotAfterIdentifier'
} ,
{
match: ':' ,
hasMicroState: 'ternary' ,
state: 'colon'
} ,
{
match: ':' ,
action: [ 'spanStyle' , 'identifier' , propertyStyle ] ,
state: 'colon'
} ,
{
match: '(' ,
subState: 'openParenthesis' ,
action: [ 'spanStyle' , 'identifier' , methodStyle ]
} ,
{
match: true ,
state: 'idleAfterValue' ,
propagate: true
}
]
} ,
dotAfterIdentifier: {
action: [ 'style' , idleStyle ] ,
branches: [
{
match: ' ' ,
state: 'dotAfterIdentifier'
} ,
{
match: /^[a-zA-Z_$]/ ,
state: 'member'
} ,
{
match: true ,
state: 'idle' ,
propagate: true
}
]
} ,
member: {
action: [ 'style' , propertyStyle ] ,
span: 'identifier' ,
branches: [
{
match: /^[a-zA-Z0-9_$]/ ,
state: 'member'
} ,
{
match: true ,
state: 'afterIdentifier' ,
propagate: true ,
continue: true
}
] ,
bufferBranches: [
{
match: specialMember ,
action: [ 'spanStyle' , 'identifier' , keywordStyle ] ,
state: 'afterIdentifier' ,
propagate: true
}
]
} ,
number: {
action: [ 'style' , numberStyle ] ,
events: [
operator: {
action: [ 'style' , idleStyle ] ,
span: 'operator' ,
branches: [
{
match: /^[0-9.]/ ,
state: 'number'
match: /^[=.<>^?!&|~*%+-]/ ,
state: 'operator'
} ,

@@ -261,19 +411,54 @@ {

state: 'idle' ,
propagate: true ,
}
] ,
bufferBranches: [
{
match: '?' ,
action: [ 'spanStyle' , 'operator' , operatorStyle ] ,
state: 'idle' ,
microState: { ternary: true } ,
propagate: true
} ,
{
match: operators ,
action: [ 'spanStyle' , 'operator' , operatorStyle ] ,
state: 'idle' ,
propagate: true
} ,
{
match: assignments ,
action: [ 'spanStyle' , 'operator' , assignmentStyle ] ,
state: 'idle' ,
propagate: true
}
]
} ,
colon: {
action: [ 'style' , operatorStyle ] ,
microState: { ternary: false } ,
branches: [
{
match: true ,
state: 'idle' ,
propagate: true
}
]
} ,
singleQuoteString: {
action: [ 'style' , stringStyle ] ,
events: [
branches: [
{
match: /^\\/ ,
state: 'escape'
match: '\\' ,
subState: 'escape'
} ,
{
match: /^['\n]/ ,
state: 'idle' ,
state: 'idleAfterValue' ,
delay: true

@@ -285,10 +470,10 @@ }

action: [ 'style' , stringStyle ] ,
events: [
branches: [
{
match: /^\\/ ,
state: 'escape'
match: '\\' ,
subState: 'escape'
} ,
{
match: /^["\n]/ ,
state: 'idle' ,
state: 'idleAfterValue' ,
delay: true

@@ -298,12 +483,76 @@ }

} ,
openBrace: {
subProgram: true , // stack a new state
action: [ 'style' , parseErrorStyle ] ,
events: [
templateString: {
action: [ 'style' , stringStyle ] ,
branches: [
{
match: '\\' ,
subState: 'escape'
} ,
{
match: '`' ,
state: 'idleAfterValue' ,
delay: true
} ,
{
match: '$' ,
state: 'templatePlaceholder'
}
]
} ,
templatePlaceholder: {
startSpan: true ,
action: [ 'style' , templatePlaceholderStyle ] ,
branches: [
{
match: '{' ,
subState: 'openBrace' ,
state: 'templateString'
} ,
{
match: true ,
state: 'idle' ,
action: [ 'spanStyle' , stringStyle ] ,
//clearSpan: true ,
state: 'templateString'
}
]
} ,
regexp: {
action: [ 'style' , regexpStyle ] ,
branches: [
{
match: '\\' ,
subState: 'escape'
} ,
{
match: /[.?+*^$]/ ,
state: 'regexpMarkup'
} ,
{
match: '[' ,
state: 'regexpOpenBracket'
} ,
{
match: '(' ,
subState: 'regexpOpenParenthesis'
} ,
{
match: ')' ,
state: 'regexpCloseParenthesis'
} ,
{
match: '|' ,
state: 'regexpAlternative'
} ,
{
match: '/' ,
state: 'closeRegexp'
}
]
} ,
closeRegexp: {
action: [ 'style' , regexpDelemiterStyle ] ,
branches: [
{
match: true ,
state: 'regexpFlag' ,
propagate: true

@@ -313,11 +562,12 @@ }

} ,
closeBrace: {
action: [ 'style' , braceStyle ] ,
events: [
regexpFlag: {
action: [ 'style' , regexpFlagStyle ] ,
branches: [
{
match: /[a-z]/ ,
state: 'regexpFlag'
} ,
{
match: true ,
return: 'openBrace' , // return (unstack), expecting returning from the 'openBrace' subProgram
action: [ 'openingStyle' , braceStyle ] ,
errorAction: [ 'style' , parseErrorStyle ] , // if not returning form 'openBrace', we've got a parseError
state: 'idle' ,
state: 'idleAfterValue' ,
propagate: true

@@ -327,9 +577,8 @@ }

} ,
openBracket: {
subProgram: true ,
action: [ 'style' , parseErrorStyle ] ,
events: [
regexpMarkup: {
action: [ 'style' , regexpMarkupStyle ] ,
branches: [
{
match: true ,
state: 'idle' ,
state: 'regexp' ,
propagate: true

@@ -339,11 +588,8 @@ }

} ,
closeBracket: {
action: [ 'style' , braceStyle ] ,
events: [
regexpAlternative: {
action: [ 'style' , regexpAlternativeStyle ] ,
branches: [
{
match: true ,
return: 'openBracket' ,
action: [ 'openingStyle' , braceStyle ] ,
errorAction: [ 'style' , parseErrorStyle ] ,
state: 'idle' ,
state: 'regexp' ,
propagate: true

@@ -353,9 +599,8 @@ }

} ,
openParenthesis: {
subProgram: true ,
regexpOpenParenthesis: {
action: [ 'style' , parseErrorStyle ] ,
events: [
branches: [
{
match: true ,
state: 'idle' ,
state: 'regexp' ,
propagate: true

@@ -365,11 +610,10 @@ }

} ,
closeParenthesis: {
action: [ 'style' , braceStyle ] ,
events: [
regexpCloseParenthesis: {
returnAfter: 'regexpOpenParenthesis' ,
action: [ [ 'style' , regexpParenthesisStyle ] , [ 'openerStyle' , regexpParenthesisStyle ] ] ,
returnErrorAction: [ 'style' , parseErrorStyle ] , // if not returning from 'openBrace', we've got a parseError
branches: [
{
match: true ,
return: 'openParenthesis' ,
action: [ 'openingStyle' , braceStyle ] ,
errorAction: [ 'style' , parseErrorStyle ] ,
state: 'idle' ,
state: 'regexp' ,
propagate: true

@@ -379,23 +623,44 @@ }

} ,
afterIdentifier: {
action: [ 'style' , idleStyle ] ,
events: [
regexpOpenBracket: {
action: [ 'style' , regexpBracketStyle ] ,
branches: [
{
match: ' ' ,
state: 'afterIdentifier'
} ,
match: true ,
state: 'regexpClass' ,
propagate: true
}
]
} ,
regexpClass: {
action: [ 'style' , regexpClassStyle ] ,
branches: [
{
match: '.' ,
state: 'dotAfterIdentifier'
match: '\\' ,
subState: 'escape'
} ,
{
match: '(' ,
state: 'openParenthesis' ,
action: [ 'blockStyle' , methodStyle ]
} ,
match: ']' ,
state: 'regexpCloseBracket'
}
]
} ,
regexpCloseBracket: {
action: [ 'style' , regexpBracketStyle ] ,
branches: [
{
match: true ,
state: 'regexp' ,
propagate: true
}
]
} ,
openBrace: {
action: [ 'style' , parseErrorStyle ] ,
//microState: { keyValuePair: true } ,
branches: [
{
match: true ,
state: 'idle' ,

@@ -406,13 +671,29 @@ propagate: true

} ,
dotAfterIdentifier: {
action: [ 'style' , idleStyle ] ,
events: [
closeBrace: {
returnAfter: 'openBrace' ,
action: [ [ 'style' , braceStyle ] , [ 'openerStyle' , braceStyle ] ] ,
returnErrorAction: [ 'style' , parseErrorStyle ] , // if not returning from 'openBrace', we've got a parseError
branches: [
{
match: ' ' ,
state: 'dotAfterIdentifier'
} ,
match: true ,
state: 'idle' ,
propagate: true
}
]
} ,
openBracket: {
action: [ 'style' , parseErrorStyle ] ,
branches: [
{
match: /^[a-zA-Z_$]/ ,
state: 'member'
} ,
match: true ,
state: 'idle' ,
propagate: true
}
]
} ,
closeBracket: {
returnAfter: 'openBracket' ,
action: [ [ 'style' , braceStyle ] , [ 'openerStyle' , braceStyle ] ] ,
returnErrorAction: [ 'style' , parseErrorStyle ] , // if not returning from 'openBrace', we've got a parseError
branches: [
{

@@ -425,23 +706,20 @@ match: true ,

} ,
member: {
action: [ 'style' , propertyStyle ] ,
events: [
openParenthesis: {
action: [ 'style' , parseErrorStyle ] ,
branches: [
{
match: /^[a-zA-Z0-9_$]/ ,
state: 'member'
} ,
{
match: true ,
state: 'afterIdentifier' ,
propagate: true ,
continue: true // continue the block
state: 'idle' ,
propagate: true
}
] ,
// Checked when an event would change the state
buffer: [
]
} ,
closeParenthesis: {
returnAfter: 'openParenthesis' ,
action: [ [ 'style' , braceStyle ] , [ 'openerStyle' , braceStyle ] ] ,
returnErrorAction: [ 'style' , parseErrorStyle ] , // if not returning from 'openBrace', we've got a parseError
branches: [
{
match: memberKeywords ,
// replace the 'action' of the event, also work with any properties of the event except 'match' BTW
action: [ 'blockStyle' , keywordStyle ] ,
state: 'afterIdentifier' ,
match: true ,
state: 'idle' ,
propagate: true

@@ -456,7 +734,7 @@ }

action: [ 'style' , idleStyle ] ,
events: [
branches: [
{
match: '/' ,
state: 'lineComment' ,
action: [ 'style' , commentStyle ]
action: [ 'streakStyle' , commentStyle ]
} ,

@@ -466,6 +744,26 @@ {

state: 'multiLineComment' ,
action: [ 'style' , commentStyle ]
action: [ 'streakStyle' , commentStyle ]
} ,
{
match: true ,
state: 'regexp' ,
action: [ 'streakStyle' , regexpDelemiterStyle ]
}
]
} ,
idleAfterValueSlash: {
action: [ 'style' , idleStyle ] ,
branches: [
{
match: '/' ,
state: 'lineComment' ,
action: [ 'streakStyle' , commentStyle ]
} ,
{
match: '*' ,
state: 'multiLineComment' ,
action: [ 'streakStyle' , commentStyle ]
} ,
{
match: true ,
state: 'idle'

@@ -477,3 +775,3 @@ }

action: [ 'style' , commentStyle ] ,
events: [
branches: [
{

@@ -487,3 +785,3 @@ match: '\n' ,

action: [ 'style' , commentStyle ] ,
events: [
branches: [
{

@@ -497,3 +795,3 @@ match: '*' ,

action: [ 'style' , commentStyle ] ,
events: [
branches: [
{

@@ -518,5 +816,4 @@ match: '/' ,

escape: {
subProgram: true ,
action: [ 'style' , escapeStyle ] ,
events: [
branches: [
{

@@ -537,2 +834,1 @@ match: true ,

/*
Text Machine
Copyright (c) 2018 Cédric Ronvel
Copyright (c) 2018 - 2022 Cédric Ronvel

@@ -6,0 +6,0 @@ The MIT License (MIT)

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